概要
实现权限验证行为的前提需要实现横切拦截设计(Spring的AOP)参考:https://www.cnblogs.com/BINGJJFLY/p/9066524.html
spring-shiro.xml配置文件的配置
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean> <bean id="authorizationAttributeSourceAdvisor" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean>
AuthorizationAttributeSourceAdvisor
public AuthorizationAttributeSourceAdvisor() { setAdvice(new AopAllianceAnnotationsAuthorizingMethodInterceptor()); }
AopAllianceAnnotationsAuthorizingMethodInterceptor
public Object invoke(MethodInvocation methodInvocation) throws Throwable { assertAuthorized(methodInvocation); return methodInvocation.proceed(); }
获得各个方法拦截器如RoleAnnotationMethodInterceptor
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); } } } }
RoleAnnotationMethodInterceptor
public void assertAuthorized(MethodInvocation mi) throws AuthorizationException { try { ((AuthorizingAnnotationHandler)getHandler()).assertAuthorized(getAnnotation(mi)); } catch(AuthorizationException ae) { // Annotation handler doesn't know why it was called, so add the information here if possible. // Don't wrap the exception here since we don't want to mask the specific exception, such as // UnauthenticatedException etc. if (ae.getCause() == null) ae.initCause(new AuthorizationException("Not authorized to invoke method: " + mi.getMethod())); throw ae; } }
RoleAnnotationHandler
public void assertAuthorized(Annotation a) throws AuthorizationException { if (!(a instanceof RequiresRoles)) return; RequiresRoles rrAnnotation = (RequiresRoles) a; String[] roles = rrAnnotation.value(); if (roles.length == 1) {
// 获得WebDelegatingSubject校验会员角色权限 getSubject().checkRole(roles[0]); return; } if (Logical.AND.equals(rrAnnotation.logical())) { getSubject().checkRoles(Arrays.asList(roles)); return; } if (Logical.OR.equals(rrAnnotation.logical())) { // Avoid processing exceptions unnecessarily - "delay" throwing the exception by calling hasRole first boolean hasAtLeastOneRole = false; for (String role : roles) if (getSubject().hasRole(role)) hasAtLeastOneRole = true; // Cause the exception if none of the role match, note that the exception message will be a bit misleading if (!hasAtLeastOneRole) getSubject().checkRole(roles[0]); } }
DelegatingSubject专门校验会员权限
Subject校验权限 --> SecurityManager校验权限 --> Realm校验权限
public void checkRole(String role) throws AuthorizationException { assertAuthzCheckPossible();
// getPrincipals()获得会员存储在数据库的信息 securityManager.checkRole(getPrincipals(), role); }
SecurityManager校验权限