分享

shiro安全框架扩展教程--如何动态修改资源权限不需要重启项目

 WindySky 2018-02-09

         大家好,感觉好长时间没有上来更新博客的样子,因为上段时间都忙着泡妞,请见谅,最后妞没泡到,只能继续伤心研究代码,之后的几个文章都是关于shiro框架的,网上关于这个框架的资料都是泛泛而谈,没有跟实际应用结合到一起,然后我把自己的一些应用心得,以及如何扩展该框架适用于我们应用项目的做法,分享给大家...大家贱笑了


        不说笑了,言归正传,我不说如何配置基本的架子了,这个大家自行去看吧,网上太多了,我只说关键点...


下面看看我的主过滤器配置

  1. <!-- 过滤链配置 -->  
  2.     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
  3.         <property name="securityManager" ref="securityManager" />  
  4.         <property name="loginUrl" value="/" />  
  5.         <property name="successUrl" value="/cms/index.do" />  
  6.         <property name="unauthorizedUrl" value="/" />  
  7.         <property name="filters">  
  8.             <map>  
  9.                 <entry key="role">  
  10.                     <bean  
  11.                         class="com.silvery.security.shiro.filter.RoleAuthorizationFilter" />  
  12.                 </entry>  
  13.                 <entry key="authc">  
  14.                     <bean  
  15.                         class="com.silvery.security.shiro.filter.SimpleFormAuthenticationFilter" />  
  16.                 </entry>  
  17.             </map>  
  18.         </property>  
  19.     </bean>  
  20.   
  21.     <!-- 权限资源配置 -->  
  22.     <bean id="filterChainDefinitionsService"  
  23.         class="com.silvery.security.shiro.service.impl.SimpleFilterChainDefinitionsService">  
  24.         <property name="definitions">  
  25.             <value>  
  26.                 /static/** = anon  
  27.                 /admin/user/login.do = anon  
  28.                 /test/** = role[user,admin]  
  29.                 /abc/** = authc  
  30.             </value>  
  31.         </property>  
  32.     </bean>  

可以看到我没有在主过滤器上配置资源,而是自己独立写的一个服务类来配置资源,为何这样做呢,下面看看我设计的这个实现类


  1. /**  
  2.  *   
  3.  * 加载第三方角色资源配置服务类  
  4.  *   
  5.  * @author shadow  
  6.  *   
  7.  */  
  8. public class SimpleFilterChainDefinitionsService extends AbstractFilterChainDefinitionsService {  
  9.   
  10.     @Override  
  11.     public Map<String, String> initOtherPermission() {  
  12.         // extend to load other permission  
  13.         return new HashMap<String, String>();  
  14.     }  
  15.   
  16. }  

很明显看到我写的方法说明,这是加载第三方资源的方法,比如说这里加载数据库资源,或者是其他文件上的配置资源,只要把资源读取出来拼成一个map返回即可,因为我们都知道shiro最终需要的是一个键值对形式的资源


既然这里是加载第三方资源的,如果没有第三方资源那直接返回一个空集合即可,那他是如何加载原始的配置资源?因为我们实际项目都知道一部分的固定资源都会写在主过滤器那里,所以考虑到的是,必须要加载一次原始的配置资源,还要再加载一次第三方资源,双管齐下即可;下面看看我的父级抽象类


  1. /**  
  2.  *   
  3.  * 安全框架角色资源配置服务类  
  4.  *   
  5.  * @author shadow  
  6.  *   
  7.  */  
  8. public abstract class AbstractFilterChainDefinitionsService implements FilterChainDefinitionsService {  
  9.   
  10.     private final static Logger log = LoggerFactory.getLogger(AbstractFilterChainDefinitionsService.class);  
  11.   
  12.     private String definitions = "";  
  13.   
  14.     @Autowired  
  15.     private ShiroFilterFactoryBean shiroFilterFactoryBean;  
  16.   
  17.     @PostConstruct  
  18.     public void intiPermission() {  
  19.         shiroFilterFactoryBean.setFilterChainDefinitionMap(obtainPermission());  
  20.         log.debug("initialize shiro permission success...");  
  21.     }  
  22.   
  23.     public void updatePermission() {  
  24.   
  25.         synchronized (shiroFilterFactoryBean) {  
  26.   
  27.             AbstractShiroFilter shiroFilter = null;  
  28.   
  29.             try {  
  30.                 shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();  
  31.             } catch (Exception e) {  
  32.                 log.error(e.getMessage());  
  33.             }  
  34.   
  35.             // 获取过滤管理器  
  36.             PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter  
  37.                     .getFilterChainResolver();  
  38.             DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();  
  39.   
  40.             // 清空初始权限配置  
  41.             manager.getFilterChains().clear();  
  42.             shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();  
  43.   
  44.             // 重新构建生成  
  45.             shiroFilterFactoryBean.setFilterChainDefinitions(definitions);  
  46.             Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();  
  47.   
  48.             for (Map.Entry<String, String> entry : chains.entrySet()) {  
  49.                 String url = entry.getKey();  
  50.                 String chainDefinition = entry.getValue().trim().replace(" ", "");  
  51.                 manager.createChain(url, chainDefinition);  
  52.             }  
  53.   
  54.             log.debug("update shiro permission success...");  
  55.         }  
  56.     }  
  57.   
  58.     /** 读取配置资源 */  
  59.     private Section obtainPermission() {  
  60.         Ini ini = new Ini();  
  61.         ini.load(definitions); // 加载资源文件节点串  
  62.         Section section = ini.getSection("urls"); // 使用默认节点  
  63.         if (CollectionUtils.isEmpty(section)) {  
  64.             section = ini.getSection(Ini.DEFAULT_SECTION_NAME); // 如不存在默认节点切割,则使用空字符转换  
  65.         }  
  66.         Map<String, String> permissionMap = initOtherPermission();  
  67.         if (permissionMap != null && !permissionMap.isEmpty()) {  
  68.             section.putAll(permissionMap);  
  69.         }  
  70.         return section;  
  71.     }  
  72.   
  73.     public abstract Map<String, String> initOtherPermission();  
  74.   
  75.     public String getDefinitions() {  
  76.         return definitions;  
  77.     }  
  78.   
  79.     public void setDefinitions(String definitions) {  
  80.         this.definitions = definitions;  
  81.     }  
  82.   
  83. }  

很明显看到为何我没有在主过滤器上配置资源,但是依然会加载资源,是由于我是手动调用了shiroFilterFactoryBean.setFilterChainDefinitionMap(obtainPermission());这个方法自动把资源设置进去;而且obtainPermission()方法中也会调用抽象接口方法加载第三方资源,所以这样就实现了我的加载原生配置,又能加载第三方资源,这样设计我觉得比较灵活


下面是另外一个重点,如何更新资源,可参考我写的updatePermission()方法,主要是清空DefaultFilterChainManager里面的FilterChains,还有shiroFilterFactoryBean里面的FilterChainDefinitions;我在网上看了好多关于这个清空资源,但是都不理想,其实是清空这两个地方,然后重新调用DefaultFilterChainManager的createChain方法,把资源重新设置进去即可,这里注意下线程安全即可


最后我把接口抽象出来,看看我的顶层接口

  1. public interface FilterChainDefinitionsService {  
  2.   
  3.     public static final String PREMISSION_STRING = "perms[{0}]"; // 资源结构格式  
  4.     public static final String ROLE_STRING = "role[{0}]"; // 角色结构格式  
  5.   
  6.     /** 初始化框架权限资源配置 */  
  7.     public abstract void intiPermission();  
  8.   
  9.     /** 重新加载框架权限资源配置 (强制线程同步) */  
  10.     public abstract void updatePermission();  
  11.   
  12.     /** 初始化第三方权限资源配置 */  
  13.     public abstract Map<String, String> initOtherPermission();  
  14. }  


最后在应用里的某个地方,从spring中获取这个接口的实例,然后调用update方法就可以动态更新配置资源


我的shiro框架心得第一个要点分享完了,谢谢大家的香蕉皮,鸡蛋壳,如需继续拍砖,敬请期待下个文章...

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多