SpringBoot + Shiro权限源码解析

根据spring aop原理,实例化spring容器对象的时候会调用到AbstractAutoProxyCreator.wrapIfNecessary()方法,该类是spring aop包下的类,不太了解spring aop的童鞋先了解一下,
该类会为符合某个条件的对象生成代理对象进而进行拦截操作执行一些业务逻辑,该方法截图如下:
在这里插入图片描述
该方法中调用了两个重要的方法,一个是getAdvicesAndAdvisorsForBean()方法一个是createProxy()方法,getAdvicesAndAdvisorsForBean()方法查找当前要实例化的对象
是否有符合条件的通知,createProxy()方法根据通知是否为空来创建代理对象。我们的 shiro项目要开启注解权限需要在spring容器中配置AuthorizationAttributeSourceAdvisor对象,截图如下:
在这里插入图片描述
该类间接实现了Pointcut接口和PointcutAdvisor接口,PointcutAdvisor实现了Advisor接口,该接口中文意思是顾问,也是实现spring aop重要的实现,它
在实现aop的通知的基础之上,在细化aop切面,通知和顾问都是切面的实现方式,通知是顾问的一个属性!顾问会通过我们的设置,将不同的通知,在不通过的时间点,把切面
织入到不同的切入点,AuthorizationAttributeSourceAdvisor只通过特定的注解才实现通知,实现了细化,这些注解一会说。在向容器中注入AuthorizationAttributeSourceAdvisor对象会调用
对象的构造方法,截图如下:
在这里插入图片描述
设置advice的属性值为AopAllianceAnnotationsAuthorizingMethodInterceptor,该类间接实现了Advice接口和MethodInterceptor接口,是个通知类,同时实现了Aop的拦截接口,在访问Cglib代理对象时候会调用到该类的
invoke方法,在构造AopAllianceAnnotationsAuthorizingMethodInterceptor对象时候初始化该对象的methodInterceptors属性,截图如下:
在这里插入图片描述
很显然构建了一些拦截器类,这些拦截器类都实现了spring aop包的MethodInterceptor接口,该接口就是进行拦截请求进行权限校验的地方,这个详细在后面说
现在分析具体请求流程,先调用了getAdvicesAndAdvisorsForBean()方法,寻找Advisor实现类,最终调用到org.springframework.aop.support.AopUtils.canApply方法,该方法中首先获取要实例化类的
所有方法,截图如下:
在这里插入图片描述
遍历方法调用AuthorizationAttributeSourceAdvisor对象的matches方法进行匹配,截图如下:
在这里插入图片描述
调用isAuthzAnnotationPresent方法进行判断该方法上是否有 RequiresPermissions.class, RequiresRoles.class,RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class注解,只要一个方法上有
就返回true,截图如下:
在这里插入图片描述
返回到wrapIfNecessary方法中调用完getAdvicesAndAdvisorsForBean()方法返回一个object数组,判断数组是否为空,如果不为空则为当前要实例化的类创建代理对象
因为我们的权限注解通常需要写在Controller层,Controller没有实现接口,所以生成的是Cglib动态代理,有兴趣的童鞋可以了解一下Cglib的原理以及生成Cglib的源码,
此处就不在介绍生成代理的源码了。

当请求带有Shiro标记的注解的Controller时候,由于Controller此时是个代理对象最终会调用到上文说到的AopAllianceAnnotationsAuthorizingMethodInterceptor的invoke方法接着调用
父类AuthorizingMethodInterceptor的invoke方法,父类的invoke方法调用了assertAuthorized()方法,截图如下:
在这里插入图片描述
该方法获取拦截器的集合,该集合是在初始化AopAllianceAnnotationsAuthorizingMethodInterceptor里面初始化的,截图如下:
在这里插入图片描述
先后添加了RoleAnnotationMethodInterceptor, PermissionAnnotationMethodInterceptor,AuthenticatedAnnotationMethodInterceptor ,UserAnnotationMethodInterceptor,GuestAnnotationMethodInterceptor拦截器,
这些拦截器又初始化了各自的handler属性,该handler是适配器模式,每个适配器适配了各自的注解类,RoleAnnotationHandler适配带有RequiresRoles注解的方法,PermissionAnnotationHandler适配带有RequiresPermissions注解的方法,
AuthenticatedAnnotationHandler适配带有RequiresAuthentication注解的方法,UserAnnotationHandler适配带有RequiresUser注解的方法,GuestAnnotationHandler适配带有RequiresGuest注解的方法,这里以方法中有RequiresPermissions注解分析源码,
其它注解方法也是类似的逻辑,有兴趣的可以自己看一下。
调用拦截器的supports方法进行方法验证是否有RequiresPermissions注解,如果有返回true,如果返回true调用拦截器的assertAuthorized方法,拦截器调用成员属性
handler的assertAuthorized方法,此时handler是PermissionAnnotationHandler,截图如下:
在这里插入图片描述
获取RequiresPermissions注解的value值形如user:add这样的字符串数组,如果字符串数组长度是1调用DefaultWebSecurityManager的checkPermission方法,最终调用到
ModularRealmAuthorizer对象的isPermitted方法,该方法截图如下:
在这里插入图片描述
获取所有自定义的Realm对象,调用对象的isPermitted方法,截图如下:
在这里插入图片描述
实例化了一个WildcardPermission对象,该对象把user:add这样的字符串分为user,add这样的集合,调用isPermitted重载方法,截图如下:
在这里插入图片描述
首先调用了getAuthorizationInfo方法获取获取该登录用户拥有的所有权限列表,首先从缓存中获取,如果缓存没有从数据库获取权限列表,然后调用
isPermitted的重载方法,截图如下:
在这里插入图片描述
判断上面查询出的权限列表是否包含Controller上指定的权限字符串,如果包含则让访问指定的Controller方法如果不包含则抛出异常信息,提示无权限,至此权限的源码分析就结束了,其他注解的判断
大同小异有兴趣的可以自己看一下。
总结:shiro根据注解生成代理对象,代理对象调用对应方法校验当前用户拥有的权限列表与方法上的权限字符串比对,如果比对成功则可以执行相应Controller的方法,
否则抛出异常信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值