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
-
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
-
-
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
-
-
Advisor
Action taken at pointcut
The enhancement action of an aspect can be pre, post, surround, etc
-
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
-
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
-
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
-
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()); } }
-
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
-
org. springframework. core. annotation. Whether annotations on a class of tools / annotations can be checked