Shiro资源权限动态配置

转载是一种动力 分享是一种美德

回顾上篇文章«SSM整合Shiro实现认证与授权»内容,主要是粗略的总结了shiro的认证流程和授权流程,知道了spring如何整合shiro实现资源访问认证与授权。本篇继续来学习shiro的使用。

本篇文章介绍如何实现资源访问权限的动态配置:

资源访问权限的动态加载

资源访问权限的动态修改

Shiro资源权限动态配置

继续使用上篇文章«SSM整合Shiro实现认证与授权»完成的Demo。在此之前我们都是在spring-shiro.xml文件中配置资源访问权限,现在我想实现的是在ShiroFilterFactoryBean初始化的时候再去数据库中读取资源访问权限配置,而且还要实现不重启服务的情况下更新Shiro的资源访问权限配置。

资源访问权限的动态加载

那么,怎么实现资源访问权限的动态加载呢?其实并不难,在spring的配置文件中给bean配置的属性都是在spring初始化这个bean的时候通过setter方法注入的,我们可以利用这一点,在需要的setter方法执行之前或之后插入我们的业务代码,亦或者重写该setter方法。

回到Shiro的配置中,在配置ShiroFilterFactoryBean的时候配置注入的属性filterChainDefinitions,其对应的setter方法就是setFilterChainDefinitions,这个方法的作用是读取注入的值,将中的字符串映射成Map类型的数据,最后调用setFilterChainDefinitionMap方法进行注入。

看了源码之后你会发现:setFilterChainDefinitions方法最终调用的是setFilterChainDefinitionMap方法,即filterChainDefinitionMap属性的setter方法。那么是否可以直接注入filterChainDefinitionMap呢?当然是可以的,下面给出个配置案例。为什么都是配置filterChainDefinitions而不是filterChainDefinitionMap呢?其实就是写法简单,配置map还需要entry-key-value,很是麻烦。

所以,我们只需要自定义一个ShiroFilterFactoryBean重写filterChainDefinitions属性的setter方法,然后在setter方法中从数据库加载资源权限配置列表,将列表转换成map数据赋值给filterChainDefinitionMap就可以实现资源权限的动态加载了。

[自定义的InitFilterChainShiroFilterFactoryBean]

修改配置文件,将ShiroFilterFactoryBean替换成InitFilterChainShiroFilterFactoryBean,然后配置给filterChainDefinitions属性注入一个空的字符串。(改动的地方我用黑色标志)

现在需要去数据库创建表和添加数据,然后还要完成创建sql映射文件和接口等工作。过程我就略了,直接给出数据和源码。

[创建资源权限分配表tb_urlperm]

perm:权限标志符

url:资源

weight:权重,Shiro匹配权限是从上往下的,所以权重是用来排序的。

[tb_urlperm测试数据]

/=anon的权重设置为0,/**=authc的权重设置一个很大的值,因为如果/=anon不是放在/**的前面就不起作用。/**=authc不放在perms[]或roles[]的后面会导致其后面的配置都不起作用。

[UrlPermMapper.xml]

UrlPerm.java(资源访问权限表对应的java类)、UrlPermDao.java、UrlPermService.java(业务接口)、UrlPermServiceImpl.java这些的代码我就不贴出来了,无非就是要实现调用UrlPermService的getFilterChainDefinitionList方法能够获取排好序的UrlPerm列表。

现在可以实现自定义的ShiroFilterFactoryBean的setFilterChainDefinitions方法了。

[InitFilterChainShiroFilterFactoryBean.java]

我们可以下断点调试一下,看看数据是否读取成功且数据的顺序是否正确。

如果spring、spring-mvc、mybatis和shiro是无配置文件整合的,可以在@Bean注解的方法,即getShiroFilterFactoryBean方法中实现资源权限的动态加载。

资源访问权限的动态修改

阅读ShiroFilterFactoryBean类的源码你会发现,我们配置注入的filterChainDefinitions只有在createFilterChainManager方法中被使用,最终调用FilterChainManager的createChain方法将资源访问权限配置一个个添加到FilterChainManager中。

DefaultFilterChainManager是FilterChainManager的一个实现类。

也就是说,FilterChainManager是负责管理资源访问权限配置的,那么我们要实现资源访问权限的动态修改就是从FilterChainManager入手的。即获取到FilterChainManager对象后,调用其getFilterChains().clear()方法可以清空当前的资源访问权限配置,调用其createChain方法可以动态添加资源访问权限。

如何获取到FilterChainManager实例?通过AbstractShiroFilter实例可以获取到FilterChainResolver实例,然后通过FilterChainResolver实例就可以获取到FilterChainManager了。

AbstractShiroFilter的实例是如何获取到的?简单,使用注解让spring自动注入就可以获取到了,因为我们在配置文件中配置了ShiroFilterFactoryBean。

ShiroFilterFactoryBean是实现了FactoryBean接口的,而ShiroFilterFactoryBean的getObject方法获取到的bean是SpringShiroFilter的实例,SpringShiroFilter又是继承至AbstractShiroFilter的。所以在配置文件中配置的 其实际是配置AbstractShiroFilter的实例。

你可能会问我是怎么知道这样获取FilterChainManager的。你可以去看ShiroFilterFactoryBean的源码,看AbstractShiroFilter实例的创建过程。(SpringShiroFilter是AbstractShiroFilter的子类。)

在获取到FilterChainManager之后我们就可以调用FilterChainManager的createChain方法添加动态权限了。

下面来看一个完整的实例吧。

首先定义一个业务接口

[DynamicPermissionService.java]

该接口只定义了一个方法:reloadPermission。让实现类实现具体的业务代码完成资源访问权限的重新加载。

DynamicPermissionService接口的实现类

[DynamicPermissionServiceImpl.java]

其中需要解析的就是reloadPermission方法,即接口中定义的方法。

reloadPermission方法要保证线程安全,在reloadPermission方法中调用了UrlPermService的getFilterChainDefinitionList方法从数据库中获取资源访问权限配置信息,获取到FilterChainManager,将当前的所有权限配置清空,再调用createChain方法添加新的权限配置。

最后写一个控制器来验证。

[UrlPermController.java]

启动服务之后到数据库中添加一条记录,即/supper/urlperm/doReload=perms[supper],然后回到浏览器访问/supper/urlperm/doReload,第一次会请求成功,而再想请求一次就会跳转到未授权页面了,说明重新加载资源访问权限配置生效了。

Demo源码下载

文中Demo源码下载地址:https://github.com/wujiuye/SSMSDemo

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180906G1DWRH00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券