shiro注解授权源码分析
2016-11-16 16:26
519 查看
老问题,要知道注解授权方式为什么能生效,首先得找到入口,相比登录的过程不同,对于这个验证权限的这个过程shiro采用了springAOP的方式
首先在spring配置文件中 我们得开启shiro的注解:
是干嘛的呢,不错就是springAOP的一种方式,这里就不多说了,具体怎样后面我自己还得学习下 ( 静态切入点)
invoke() 看到此类中的invoke方法
查看PermissionAnnotationHandler的对应方法
查看checkPermission方法
权限字符串然后返回过来了
最后就是比较权限字符串是否包含权限注解中的字符串了
首先在spring配置文件中 我们得开启shiro的注解:
<!-- 开启shiro注解支持--> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean>那么我们的入口就找到了,AuthorizationAttributeSourceAdvisor类继承了StaticMethodMatcherPointcutAdvisor类,至于这个StaticMethodMatcherPointcutAdvisor类
是干嘛的呢,不错就是springAOP的一种方式,这里就不多说了,具体怎样后面我自己还得学习下 ( 静态切入点)
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. */ 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; } //The 'method' parameter could be from an interface that doesn't have the annotation. //Check to see if the implementation has it. if ( targetClass != null) { try { m = targetClass.getMethod(m.getName(), m.getParameterTypes()); if ( isAuthzAnnotationPresent(m) ) { return true; } } 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(Method method) { for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) { Annotation a = AnnotationUtils.findAnnotation(method, annClass); if ( a != null ) { return true; } } return false; } }构造函数中调用了setAdvice方法,传入参数为匿名AopAllianceAnnotationsAuthorizingMethodInterceptor类对象
public AopAllianceAnnotationsAuthorizingMethodInterceptor() { List<AuthorizingAnnotationMethodInterceptor> interceptors = new ArrayList<AuthorizingAnnotationMethodInterceptor>(5); AnnotationResolver resolver = new SpringAnnotationResolver(); //we can re-use the same resolver instance - it does not retain state: 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); }这里按照Permission分析 PermissionAnnotationMethodInterceptor的带参构造函数
public PermissionAnnotationMethodInterceptor(AnnotationResolver resolver) { super( new PermissionAnnotationHandler(), resolver); }调用父类构造函数并且第一个参数 字面意思可以看出 是对 权限注解的处理类,父类为AuthorizingAnnotationMethodInterceptor,一般我们知道AOP 执行的方法为
invoke() 看到此类中的invoke方法
public Object invoke(MethodInvocation methodInvocation) throws Throwable { assertAuthorized(methodInvocation); return methodInvocation.proceed(); }可以看到其中调用了assertAuthorized方法
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; } }其中((AuthorizingAnnotationHandler)getHandler()).assertAuthorized(getAnnotation(mi));这行代码实际就是调用我们之前传入的注解处理类的assertAuthorized方法
查看PermissionAnnotationHandler的对应方法
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())) { // Avoid processing exceptions unnecessarily - "delay" throwing the exception by calling hasRole first boolean hasAtLeastOnePermission = false; for (String permission : perms) if (getSubject().isPermitted(permission)) hasAtLeastOnePermission = true; // Cause the exception if none of the role match, note that the exception message will be a bit misleading if (!hasAtLeastOnePermission) getSubject().checkPermission(perms[0]); } }代码分析,前面就不用说了获取subject,获取注解的permission字符串 以一个字符串分析
查看checkPermission方法
public void checkPermission(String permission) throws AuthorizationException { assertAuthzCheckPossible(); securityManager.checkPermission(getPrincipals(), permission); }继续看securityManager的checkPermission方法,中间类似方法的调用 最后在ModularRealmAuthorizer中
public void checkPermission(PrincipalCollection principals, String permission) throws AuthorizationException { assertRealmsConfigured(); if (!isPermitted(principals, permission)) { throw new UnauthorizedException("Subject does not have permission [" + permission + "]"); } }if语句中判断是否满足条件
public boolean isPermitted(PrincipalCollection principals, String permission) { assertRealmsConfigured(); for (Realm realm : getRealms()) { if (!(realm instanceof Authorizer)) continue; if (((Authorizer) realm).isPermitted(principals, permission)) { return true; } } return false; }最后调到AuthorizingRealm的isPermitted方法 这里就不啰嗦了
public boolean isPermitted(PrincipalCollection principals, Permission permission) { AuthorizationInfo info = getAuthorizationInfo(principals); return isPermitted(permission, info); }getAuthorizationInfo方法为
protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) { if (principals == null) { return null; } AuthorizationInfo info = null; if (log.isTraceEnabled()) { log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]"); } Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache(); if (cache != null) { if (log.isTraceEnabled()) { log.trace("Attempting to retrieve the AuthorizationInfo from cache."); } Object key = getAuthorizationCacheKey(principals); info = cache.get(key); if (log.isTraceEnabled()) { if (info == null) { log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]"); } else { log.trace("AuthorizationInfo found in cache for principals [" + principals + "]"); } } } if (info == null) { // Call template method if the info was not found in a cache info = doGetAuthorizationInfo(principals); // If the info is not null and the cache has been created, then cache the authorization info. if (info != null && cache != null) { if (log.isTraceEnabled()) { log.trace("Caching authorization info for principals: [" + principals + "]."); } Object key = getAuthorizationCacheKey(principals); cache.put(key, info); } } return info; }上面同样是从缓存中取,直接看下面 ,doGetAuthorizationInfo()方法 有没有很眼熟,没错 就是我们自定义realm里面可以拓展的方法,一般就是从数据库获取配置的
权限字符串然后返回过来了
最后就是比较权限字符串是否包含权限注解中的字符串了
protected boolean isPermitted(Permission permission, AuthorizationInfo info) { Collection<Permission> perms = getPermissions(info); if (perms != null && !perms.isEmpty()) { for (Permission perm : perms) { if (perm.implies(permission)) { return true; } } } return false; }当然没满足就会抛出没有权限的异常了
相关文章推荐
- 源码分析shiro认证授权流程
- shiro认证授权流程源码分析
- 源码分析shiro认证授权流程
- 源码分析shiro认证授权流程
- Shiro源码分析----授权流程
- Shiro授权过程--源码分析
- 源码分析shiro认证授权流程
- Shiro认证与授权源码分析
- Shiro源码分析-----认证流程/授权流程----------Subject
- Shiro用户登录认证、权限授权示例,以及源码分析(上)
- Shiro源码分析 - 授权流程
- 【转载】源码分析shiro认证授权流程
- 源码分析shiro认证授权流程
- Shiro源码分析-----认证流程/授权流程----------Subject
- shiro认证授权源码分析
- 从源码分析 Spring 基于注解的事务
- Shiro简单授权原理分析
- shiro学习笔记——从源码角度分析shiro身份验证过程
- [授权发表]源码分析:动态分析 C 程序函数调用关系
- opencv的hog源码分析(详细的hog.cpp注解)