shiro的动态权限管理
上次捋shiro底层源码没多久,这次面临了新的需求,如何在实现shiro的权限动态管理。
为什么呢?

我们一般配置shiro,都是这样配置它的过滤器链。而且上次也说过,shiro的拦截器配置从上到下的顺序配置,一旦有一个路径可以包括后边的,那么后边的过滤器就作废了。
当访问路径少的时候,这样是没问题的,但是假如拦截的访问路径很多,这种写在xml配置文件中的数据改起来会很麻烦,而且,每次改动都要重启服务器。
为了解决这个问题,所以提供了shiro的动态权限操作。
所谓动态权限操作,就是把过滤器配置放在数据库中,不论获取还是修改,都是修改数据库的数据,并且实时更新。
核心在于ShiroFilterFactoryBean的setFilterChainDefinitions方法。
根据经验,其实可以分为两部分来看。
1.纯获取
只是单纯的把数据放在数据库中,并不涉及修改。
只需要自己定义一个继承自ShiroFilterFactoryBean的类,重写setFilterChainDefinitions,在这个方法中获取数据库中的数据就可以了。
package org.magicabc.pc.shiro; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.shiro.config.Ini; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.util.CollectionUtils; import org.apache.shiro.web.config.IniFilterChainResolverFactory; import org.magicabc.bean.Permissions; import org.magicabc.service.IShiroPermissionsService; import org.springframework.beans.factory.annotation.Autowired; /** * @ClassName: ShiroPermissionFactory * @Description: 自定义的的shirofilterfactorybean,setFilterChainDefinitions进行重写,用来从数据库中获取权限相关数据 * @author yangxu * @date 2018年1月2日 * */ public class ShiroPermissionFactory extends ShiroFilterFactoryBean { /*配置中的过滤链*/ public static String definitions; /**权限service*/ @Autowired private IShiroPermissionsService shiroPermissionsService; /** * 初始化设置过滤链 */ @Override public void setFilterChainDefinitions(String definitions) { ShiroPermissionFactory.definitions = definitions;//记录配置的静态过滤链 //数据库动态权限 List<Permissions> permissions = shiroPermissionsService.getPermissions(); Map<String, String> otherChains = new HashMap<String, String>(); for(Permissions po : permissions){ //字符串拼接权限 otherChains.put(po.getUrl(), po.getName()); } otherChains.put("/**", "authc"); //从配置文件加载权限配置 Ini ini = new Ini(); ini.load(definitions); Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS); if (CollectionUtils.isEmpty(section)) { section = ini.getSection(Ini.DEFAULT_SECTION_NAME); } //加上数据库中过滤链 section.putAll(otherChains); setFilterChainDefinitionMap(section); } }
然后修改配置文件

项目启动时,会自动加载这个ShiroPermissionFactory类,并执行其中的setFilterChainDefinitions方法。
2.动态修改
如果要实现动态修改,需要定义service来实现滤器链和数据库的数据同步
package org.magicabc.pc.shiro; import java.util.Map; import javax.annotation.Resource; import org.apache.shiro.util.CollectionUtils; import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager; import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; import org.apache.shiro.web.servlet.AbstractShiroFilter; import org.magicabc.service.FilterChainDefinitionsService; import org.springframework.stereotype.Service; /** * @ClassName: FilterChainDefinitionsService * @Description: 对后台权限数据库进行增删改操作的时候需要调用这个service,用以保证拦截链的同步 * @author yangxu * @date 2018年1月2日 * */ @Service("filterChainDefinitionsService") public class FilterChainDefinitionsServiceImpl implements FilterChainDefinitionsService{ @Resource private ShiroPermissionFactory shiroPermissionFactory; @Override public void reloadFilterChains() { synchronized(shiroPermissionFactory){ AbstractShiroFilter shiroFilter = null; try { shiroFilter = (AbstractShiroFilter) shiroPermissionFactory.getObject(); PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) shiroFilter .getFilterChainResolver(); // 过滤管理器 DefaultFilterChainManager manager = (DefaultFilterChainManager) resolver.getFilterChainManager(); // 清除权限配置 manager.getFilterChains().clear(); shiroPermissionFactory.getFilterChainDefinitionMap().clear(); // 重新设置权限 shiroPermissionFactory.setFilterChainDefinitions(ShiroPermissionFactory.definitions);//传入配置中的filterchains Map<String, String> chains = shiroPermissionFactory.getFilterChainDefinitionMap(); //重新生成过滤链 if (!CollectionUtils.isEmpty(chains)) { chains.forEach((url, definitionChains) -> { manager.createChain(url, definitionChains.trim().replace(" ", "")); }); } } catch (Exception e) { e.printStackTrace(); } } } }
synchronized代码块保证了强制同步
之后,就是创建自己的Controller,然后在Controller中执行对权限的增删改操作时,需要调用FilterChainDefinitionsServiceImpl中的reloadFilterChains()方法
这样,就对过滤器链进行了动态同步操作。

浙公网安备 33010602011771号