shiro@RequiresPermission Verification implementation

shiro-spring

Annotation verification of shiro with the help of Spring AOP feature

After introducing shiro spring dependency, be sure to inject AuthorizationAttributeSourceAdvisor to verify shiro annotation with spring aop

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

 

 

StaticMethodMatcherPointcut

How to access the spring framework and realize its own AOP operation with the help of spring

An abstract class implements pointcutadvisor, ordered and serializable interfaces

public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut

This is a bridge pattern. The Pointcut interface represents a Pointcut, but extensions staticmethodmatcher represents that this abstract class is more suitable to be represented as a method matcher. A Pointcut + method matching aggregate abstract class allows the expansion of two dimensions

A convenient super class with two dimensions,

Some spring AOP related interfaces

StaticMethodMatcherPointcut integrates two important interfaces described in spring AOP

  1. MethodMatcher

    An abstract interface used to determine whether a method can be enhanced

    • TrueMethodMatcher

      The singleton pattern implemented by a hungry man is a Canonical matcher that matches all methods

      The matches method that implements 3-arg throws an exception directly, which means that the method cannot be called at runtime

          @Override
          public boolean matches(Method method, Class<?> targetClass, Object... args) {
              // Should never be invoked as isRuntime returns false.
              throw new UnsupportedOperationException();
          }

       

    • boolean matches(Method method, Class<?> targetClass); Execute static to check whether the target method meets the enhanced conditions

    • boolean isRuntime(); Does the runtime need to call Boolean matches (method, method, class <? > targetclass, object... Args);, Even if the matches method of parameter 2 is judged to be true

    • boolean matches(Method method, Class<?> targetClass, Object... args); Only the matches method of 2-arg is called and returns true, and isRuntime also returns true. This method is immediately called to judge whether it is dynamically judged at runtime

  2. Pointcut

    The pointcut abstract interface is composed of classFilter and MethodMatcher

    All network requests have filters in the servlet to implement the crosscutting interception processing of AOP, so class can also have its own ClassFilter in the AOP implementation

    • ClassFilter getClassFilter(); Get class filter

    • Return the MethodMatcher for this pointcut. Gets the method matcher of the pointcut

  3. Advisor

    Action taken at pointcut

    The enhancement action of an aspect can be pre, post, surround, etc

  4.  

 

StaticMethodMatcherPointcut will implement a large number of abstractions, leaving only the most important 2-arg method match

A methodMatcher who wants to become a pointcut

 

StaticMethodMatcherPointcutAdvisor

public abstract class StaticMethodMatcherPointcutAdvisor extends StaticMethodMatcherPointcut
      implements PointcutAdvisor, Ordered, Serializable

A superclass with enhanced methods and pointcut dual identity

Subclasses that inherit this abstract class only need to implement whether a method matches the method that needs to be enhanced. Boolean matches (method, method, class <? > targetclass);

Implementation of annotated security verification with spring

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.shiro.spring.security.interceptor;
​
import org.apache.shiro.authz.annotation.*;
import org.apache.shiro.mgt.SecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.core.annotation.AnnotationUtils;
​
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
​
​
/**
 * TODO - complete JavaDoc
 *
 * @since 0.1
 */
@SuppressWarnings({"unchecked"})
public class AuthorizationAttributeSourceAdvisor extends StaticMethodMatcherPointcutAdvisor {
​
    private static final Logger log = LoggerFactory.getLogger(AuthorizationAttributeSourceAdvisor.class);
​
    private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
            new Class[] {
                    RequiresPermissions.class, RequiresRoles.class,
                    RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class
            };
​
    protected SecurityManager securityManager = null;
​
    /**
     * Create a new AuthorizationAttributeSourceAdvisor.
     * Initialize injection enhancement action (verify user identity / authority)
     */
    public AuthorizationAttributeSourceAdvisor() {
        setAdvice(new AopAllianceAnnotationsAuthorizingMethodInterceptor());
    }
​
    public SecurityManager getSecurityManager() {
        return securityManager;
    }
​
    public void setSecurityManager(org.apache.shiro.mgt.SecurityManager securityManager) {
        this.securityManager = securityManager;
    }
​
    /**
     * Realize method matching, find the method marked shiro related annotation, and make it a pointcut
     * Returns <tt>true</tt> if the method or the class has any Shiro annotations, false otherwise.
     * The annotations inspected are:
     * <ul>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresAuthentication RequiresAuthentication}</li>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser}</li>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest}</li>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles}</li>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions}</li>
     * </ul>
     *
     * @param method      the method to check for a Shiro annotation
     * @param targetClass the class potentially declaring Shiro annotations
     * @return <tt>true</tt> if the method has a Shiro annotation, false otherwise.
     * @see org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, Class)
     */
    public boolean matches(Method method, Class targetClass) {
        Method m = method;
        // Judge whether the current method has annotation related to shiro verification
        if ( isAuthzAnnotationPresent(m) ) {
            return true;
        }
​
        //The 'method' parameter could be from an interface that doesn't have the annotation.
        //Check to see if the implementation has it.
        // Method has an inheritance relationship. Find out whether the implementation class (method) is marked
        if ( targetClass != null) {
            try {
                m = targetClass.getMethod(m.getName(), m.getParameterTypes());
                return isAuthzAnnotationPresent(m) || isAuthzAnnotationPresent(targetClass);
            } catch (NoSuchMethodException ignored) {
                //default return value is false.  If we can't find the method, then obviously
                //there is no annotation, so just use the default return value.
            }
        }
​
        return false;
    }
​
    private boolean isAuthzAnnotationPresent(Class<?> targetClazz) {
        for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) {
            Annotation a = AnnotationUtils.findAnnotation(targetClazz, annClass);
            if ( a != null ) {
                return true;
            }
        }
        return false;
    }
​
    /**
     * Is shiro permission verification related annotation marked on the verification method
     */
    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;
    }
​
}
​

 

 

Summary

Through the IOC+AOP feature of Spring, a pointcut detector is injected into the IOC container. Due to the AOP feature, dynamic section detection is carried out and enhanced operation is carried out for the matched pointcut

@RequiresPermission annotation verification process

  1. Whether the AuthorizationAttributeSourceAdvisor#matches verification method is annotated with shiro. Here, it is mainly used to verify whether the @ RequiresPermission annotation is added

    The following is the AOP process of spring framework

    Called by defaultadvisorchainfactory #getinterceptorsanddynamicinception advice

    Called by advisedsupport#getinterceptorsanddynamicinception advice

  2. Call PermissionAnnotationHandler to process the @ RequiresPermissions annotation. Take out the subject stored in the current thread session according to the ThreadContext to judge whether the current login user has a certain permission. The user permission is stored in the cache by shiro (redis can be used to save the serialized data of shiro's user authorization information here)

 

Some authorization verification actions go back to the cache to obtain the authorization information cached by the currently logged in user (in a session). Therefore, cache cleaning is required to perform user switching / user permission change

    /**
     * Delete authorization cache according to principalCollection
     * @param attribute
     */
    public void deleteCacheBySimplePrincipalCollection(SimplePrincipalCollection attribute) {
        //Delete the Cache and re authorize when accessing the restricted interface
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        Authenticator authc = securityManager.getAuthenticator();
        ((LogoutAware) authc).onLogout(attribute);
    }

Subject. Can be called Runas for user identity switching

 

doubt

  1. Does the abstract class implement the methodMatcher without implementing all the methods and will not report an error

    No, the abstract class is an abstract description, which means that there is no need to implement any method in the interface that is also an abstract description, but the specific implementation class is different. If an interface in the inherited interface has no default implementation, it must be implemented, otherwise an error will be reported when running

    Class 'ConcreteStaticMethodMatcher' must either be declared abstract or implement abstract method 'matches(Method, Class<?>)' in 'MethodMatcher'

    package priv.wzb.javabase.abstractAndInterface;
    ​
    import java.lang.reflect.Method;
    ​
    /**
     * @program: Design_Pattern
     * @author: yuzuki
     * @create: 2021-05-29 13:38
     * @description: AOP_Method matching interface
     **/
    public interface MethodMatcher {
        /**
         * method In AOP, whether the method is a join point / tangent point
         * @param method
         * @param targetClass
         * @return
         */
        boolean matches(Method method,Class<?> targetClass);
    ​
        /**
         * Do you need to dynamically call 3-arg matching after matching
         * @return
         */
        boolean isRuntime();
    ​
        /**
         * matchers=true isRuntime=true Time trigger
         * @param method
         * @param targetClass
         * @param args
         * @return
         */
        boolean methes(Method method,Class<?> targetClass,Object... args);
    }
    package priv.wzb.javabase.abstractAndInterface;
    ​
    import java.lang.reflect.Method;
    ​
    /**
     * @program: Design_Pattern
     * @author: wangzibai01
     * @create: 2021-05-29 13:45
     * @description: Static method detection
     **/
    ​
    public abstract class StaticMethodMatcher implements MethodMatcher {
        @Override
        public boolean isRuntime() {
            return false;
        }
    ​
        @Override
        public boolean methes(Method method, Class<?> targetClass, Object... args) {
    //      return false;
            throw new UnsupportedOperationException();
        }
    }
    ​
    package priv.wzb.javabase.abstractAndInterface;
    ​
    import java.lang.reflect.Method;
    ​
    /**
     * @program: Design_Pattern
     * @author: wangzibai01
     * @create: 2021-05-29 13:46
     * @description: StaticMethodMatcher Implementation class
     **/
    ​
    public class ConcreteStaticMethodMatcher extends StaticMethodMatcher {
        @Override
        public boolean matches(Method method, Class<?> targetClass) {
            return false;
        }
        public static void main(String[] args) {
            System.out.println("new ConcreteStaticMethodMatcher().isRuntime() = " + new ConcreteStaticMethodMatcher().isRuntime());
        }
    }
    ​

     

  2. Generics and wildcards

    The difference between empty type and wildcard

    Lack of type: specify the type abstractly, which makes it more convenient for developers to use, and plays a role in optimization and design. Generics can prevent the disappearance of class features. Wildcards: specify the type range, avoid the development of the range that the data only supports, and set the wrong type to cause bug s. Flexible use

  3. org. springframework. core. annotation. Whether annotations on a class of tools / annotations can be checked

Keywords: Java Shiro Spring AOP

Added by ow-phil on Tue, 08 Feb 2022 01:58:11 +0200