Shiro rights principles comment

1 | 0 Overview

Not long ago learned how to use the authority notes (), began to think about a lot. Implementation is initially guess annotations @Aspect, like the following specific implementation (the audit log recording section). Later I found not the case, so specifically analyze the source code.
@Component
@Aspect
public class AuditLogAspectConfig {
    @Pointcut ( "Annotation @ (com.ygsoft.ecp.mapp.basic.audit.annotation.AuditLog) || @annotation (com.ygsoft.ecp.mapp.basic.audit.annotation. AuditLogs) ")
    public void the pointcut () {       
    }

    @After (value = "the pointcut ()")
    public void After (the JoinPoint Joinpoint) {
        // perform logic
    }
    ...
}

0 annotated source code analysis permissions | 2

DefaultAdvisorAutoProxyCreator BeanProcessor This class implements the interface, when the ApplicationContext Bean read all configuration information, This class will scan context, to find all Advistor (Advisor is a starting point and a composition of a notification), these apply to all eligible Advisor the starting point of the Bean.
@Configuration
public class ShiroAnnotationProcessorConfiguration the extends AbstractShiroAnnotationProcessorConfiguration {
    @Bean
    @DependsOn ( "lifecycleBeanPostProcessor")
    protected DefaultAdvisorAutoProxyCreator The DefaultAdvisorAutoProxyCreator () {
        return super.defaultAdvisorAutoProxyCreator ();
    }

    @Bean
    protected AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        return super.authorizationAttributeSourceAdvisor(securityManager);
    }

}

AuthorizationAttributeSourceAdvisor inherited StaticMethodMatcherPointcutAdvisor, as shown in the following code, only five matching annotation, class or method that is only five of these annotations marked enhancement. StaticMethodMatcherPointcutAdvisor static method is an abstract base class tangent point, it matches all default classes. StaticMethodMatcherPointcut comprises two major subclasses are NameMatchMethodPointcut and AbstractRegexpMethodPointcut, in front of the former provides a simple string matching method, while the latter in front of a regular expression matching. Dynamic method tangent point: DynamicMethodMatcerPointcut dynamic method is an abstract base class cut point, by default it matches all of the classes, but also outdated, and recommended DefaultPointcutAdvisor DynamicMethodMatcherPointcut dynamic method instead. Also we need to focus constructor incoming AopAllianceAnnotationsAuthorizingMethodInterceptor.
public class AuthorizationAttributeSourceAdvisor extends StaticMethodMatcherPointcutAdvisor {

    private static final Logger log = LoggerFactory.getLogger(AuthorizationAttributeSourceAdvisor.class);

    protected SecurityManager securityManager = null;

    public AuthorizationAttributeSourceAdvisor() {
        setAdvice(new AopAllianceAnnotationsAuthorizingMethodInterceptor());
    }

    public SecurityManager getSecurityManager() {
        return securityManager;
    }

    public void setSecurityManager(org.apache.shiro.mgt.SecurityManager securityManager) {
        this.securityManager = securityManager;
    }

    public boolean matches(Method method, Class targetClass) {
        Method m = method;

        if ( isAuthzAnnotationPresent(m) ) {
            return true;
        }
       
        if ( targetClass != null) {
            try {
                m = targetClass.getMethod(m.getName(), m.getParameterTypes());
                if ( isAuthzAnnotationPresent(m) ) {
                    return true;
                }
            } catch (NoSuchMethodException ignored) {
               
            }
        }

        return false;
    }

    private boolean isAuthzAnnotationPresent(Method method) {
        for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) {
            Annotation a = AnnotationUtils.findAnnotation(method, annClass);
            if ( a != null ) {
                return true;
            }
        }
        return false;
    }

}

AopAllianceAnnotationsAuthorizingMethodInterceptor At initialization, interceptors added five methods interceptor (both inherited from AuthorizingAnnotationMethodInterceptor), five interceptors are five kinds of method validation permission to intercept execution invoke methods.
AopAllianceAnnotationsAuthorizingMethodInterceptor class public
        the extends the implements MethodInterceptor {AnnotationsAuthorizingMethodInterceptor

    public AopAllianceAnnotationsAuthorizingMethodInterceptor() {
        List<AuthorizingAnnotationMethodInterceptor> interceptors =
                new ArrayList<AuthorizingAnnotationMethodInterceptor>(5);
        AnnotationResolver resolver = new SpringAnnotationResolver();
       
        interceptors.add(new RoleAnnotationMethodInterceptor(resolver));
        interceptors.add(new PermissionAnnotationMethodInterceptor(resolver));
        interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver));
        interceptors.add(new UserAnnotationMethodInterceptor(resolver));
        interceptors.add(new GuestAnnotationMethodInterceptor(resolver));
        setMethodInterceptors(interceptors);
    }
   
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation);
        return super.invoke(mi);
    }
    ...
}

AopAllianceAnnotationsAuthorizingMethodInterceptor invoke method, will call the invoke method of the superclass AuthorizingMethodInterceptor, perform assertAuthorized method In this method, permissions check, the check is not passed, throw AuthorizationException exception, interrupt method; by check, perform methodInvocation. proceed (), which is intercepted and needs permission verification method.
public abstract class AuthorizingMethodInterceptor extends MethodInterceptorSupport {

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        assertAuthorized(methodInvocation);
        return methodInvocation.proceed();
    }

    protected abstract void assertAuthorized(MethodInvocation methodInvocation) throws AuthorizationException;
}

assertAuthorized方法最终执行的还是AuthorizingAnnotationMethodInterceptor.assertAuthorized,而AuthorizingAnnotationMethodInterceptor有5中的具体的实现类(RoleAnnotationMethodInterceptor, PermissionAnnotationMethodInterceptor, AuthenticatedAnnotationMethodInterceptor, UserAnnotationMethodInterceptor, GuestAnnotationMethodInterceptor)。
public abstract class AnnotationsAuthorizingMethodInterceptor extends  AuthorizingMethodInterceptor {
 
    protected void assertAuthorized(MethodInvocation methodInvocation) throws AuthorizationException {
        //default implementation just ensures no deny votes are cast:
        Collection<AuthorizingAnnotationMethodInterceptor> aamis = getMethodInterceptors();
        if (aamis != null && !aamis.isEmpty()) {
            for (AuthorizingAnnotationMethodInterceptor aami : aamis) {
                if (aami.supports(methodInvocation)) {
                    aami.assertAuthorized(methodInvocation);
                }
            }
        }
    }
    ...
}

AuthorizingAnnotationMethodInterceptor of assertAuthorized, first obtain AuthorizingAnnotationHandler from the subclass, then call assertAuthorized method implementation class.
the extends AnnotationMethodInterceptor AuthorizingAnnotationMethodInterceptor abstract class public
{

    public AuthorizingAnnotationMethodInterceptor( AuthorizingAnnotationHandler handler ) {
        super(handler);
    }

    public AuthorizingAnnotationMethodInterceptor( AuthorizingAnnotationHandler handler,
                                                  AnnotationResolver resolver) {
        super(handler, resolver);
    }

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        assertAuthorized(methodInvocation);
        return methodInvocation.proceed();
    }

    public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
        try {
            ((AuthorizingAnnotationHandler)getHandler()).assertAuthorized(getAnnotation(mi));
        }
        catch(AuthorizationException ae) {
            if (ae.getCause() == null) ae.initCause(new AuthorizationException("Not authorized to invoke method: " + mi.getMethod()));
            throw ae;
        }       
    }
}

Now one implementation class PermissionAnnotationMethodInterceptor analysis, are most used, however small the actual code for this class, it is clear that the above analysis getHandler PermissionAnnotationHandler return value in the PermissionAnnotationMethodInterceptor.
public class PermissionAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {

    public PermissionAnnotationMethodInterceptor() {
        super( new PermissionAnnotationHandler() );
    }

 
    public PermissionAnnotationMethodInterceptor(AnnotationResolver resolver) {
        super( new PermissionAnnotationHandler(), resolver);
    }
}

In PermissionAnnotationHandler class, finally we found the actual test logic, or call Subject.checkPermission () for verification.
public class PermissionAnnotationHandler extends AuthorizingAnnotationHandler {

    public PermissionAnnotationHandler() {
        super(RequiresPermissions.class);
    }

    protected String[] getAnnotationValue(Annotation a) {
        RequiresPermissions rpAnnotation = (RequiresPermissions) a;
        return rpAnnotation.value();
    }

    public void assertAuthorized(Annotation a) throws AuthorizationException {
        if (!(a instanceof RequiresPermissions)) return;

        RequiresPermissions rpAnnotation = (RequiresPermissions) a;
        String[] perms = getAnnotationValue(a);
        Subject subject = getSubject();

        if (perms.length == 1) {
            subject.checkPermission(perms[0]);
            return;
        }
        if (Logical.AND.equals(rpAnnotation.logical())) {
            getSubject().checkPermissions(perms);
            return;
        }
        if (Logical.OR.equals(rpAnnotation.logical())) {
            boolean hasAtLeastOnePermission = false;
            for (String permission : perms) if (getSubject().isPermitted(permission)) hasAtLeastOnePermission = true;
            if (!hasAtLeastOnePermission) getSubject().checkPermission(perms[0]);
           
        }
    }
}

3 | 0 achieve a similar programmatic AOP

Define an annotation
@Target (ElementType.METHOD {})
@Retention (RetentionPolicy.RUNTIME)
public @interface the Log {
    String value () default "";
}

StaticMethodMatcherPointcutAdvisor class inheritance, and related methods.
@SuppressWarnings ( "Serial")
@Component
public class HelloAdvisor the extends StaticMethodMatcherPointcutAdvisor {
   
    public HelloAdvisor () {
        setAdvice (new new LogMethodInterceptor ());
    }

    public boolean matches(Method method, Class targetClass) {
        Method m = method;
        if ( isAuthzAnnotationPresent(m) ) {
            return true;
        }

        if ( targetClass != null) {
            try {
                m = targetClass.getMethod(m.getName(), m.getParameterTypes());
                return isAuthzAnnotationPresent(m);
            } catch (NoSuchMethodException ignored) {
             
            }
        }
        return false;
    }

    private boolean isAuthzAnnotationPresent(Method method) {
        Annotation a = AnnotationUtils.findAnnotation(method, Log.class);
        return a!= null;
    }
}

MethodInterceptor implement the interface definition logic processing section
public class LogMethodInterceptor implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {
        Log log = invocation.getMethod().getAnnotation(Log.class);
        System.out.println("log: "+log.value());
        return invocation.proceed();   
    }
}

Define a test class, and add annotations Log
@Component
public class TestHello {

    @Log("test log")
    public String say() {
        return "ss";
    }
}

Class start writing, and the configuration The DefaultAdvisorAutoProxyCreator
@Configuration
public class TestBoot {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext("com.fzsyw.test"); 
        TestHello th = ctx.getBean(TestHello.class);
        System.out.println(th.say());
    }
   
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator da = new DefaultAdvisorAutoProxyCreator();
        da.setProxyTargetClass(true);
        return da;
    }
}

The final results are printed below, demonstrate programmatic AOP effect.
log: the Test log
SS

4 | 0 Summary and Thinking

Shiro comments permissions, really easy to use, but also by analyzing its source code implementation principle is more central configuration DefaultAdvisorAutoProxyCreator and inheritance StaticMethodMatcherPointcutAdvisor. Five of the authority notes, using a unified set of code architecture, uses a template model to facilitate the expansion. Finally, it is simply made a small example, a better understanding of programmatic AOP.

Guess you like

Origin www.linuxidc.com/Linux/2019-08/160250.htm