shiro不重啟動態加載權限


最近一朋友讓我幫他做一個后台權限管理的項目。我就在我原來的項目加加改改但是還是不理想,查了不少資料也走了不了彎路。。。。。。

shiro基本的配置我就不多說了這個很簡單自己查查資料就完成…………下面是基本的配置不多說,如果這個靜態的都不會配置那么就沒必要繼續往下看了,要稍微了解一點shiro的知識。另外要想動態加載權限的……思路就是重寫ShiroFilterFactoryBean類中的setFilterChainDefinitions()方法

<bean id="myShiro" class="com.agnils.base.user.service.MyShiro">  
  <!--  <property name="userService" ref="userService"/>   --> 
  </bean>
    <!-- 配置權限管理器 -->  
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">    
        <!-- ref對應我們寫的realm  MyShiro -->  
        <property name="realm" ref="myShiro"/>    
        <!-- 使用下面配置的緩存管理器 -->  
        <property name="cacheManager" ref="cacheManager"/>   
    </bean>  
      
    <!-- 配置shiro的過濾器工廠類,id- shiroFilter要和我們在web.xml中配置的過濾器一致 -->  
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">   
        <!-- 調用我們配置的權限管理器 -->   
        <property name="securityManager" ref="securityManager"/>   
        <!-- 配置我們的登錄請求地址 -->   
        <property name="loginUrl" value="/login"/>    
        <!-- 配置我們在登錄頁登錄成功后的跳轉地址,如果你訪問的是非/login地址,則跳到您訪問的地址 -->  
        <property name="successUrl" value="/index"/>    
        <!-- 如果您請求的資源不再您的權限范圍,則跳轉到/403請求地址 -->  
        <property name="unauthorizedUrl" value="/403"/>    
        <!-- 權限配置 -->  
        <property name="filterChainDefinitions">    
            <value>    
                <!-- anon表示此地址不需要任何權限即可訪問 -->  
                /static/**=anon  
                /uploadImg/**=anon 
                <!-- perms[user:query]表示訪問此連接需要權限為user:query的用戶 -->  
                /user=perms[user:query]  
                <!-- roles[manager]表示訪問此連接需要用戶的角色為manager -->  
                /user/add=roles[manager]
                /user/del/**=roles[admin]  
                /user/edit/**=roles[manager]
                /store/add=anon  
                /store/addStore=roles[manager] 
                /item/sale/**=roles[manager]
                /login=anon 
                /customLogin=anon 
                /ordering/**=anon
                /register=anon
                /register/**=anon
                <!--所有的請求(除去配置的靜態資源請求或請求地址為anon的請求)都要通過登錄驗證,如果未登錄則跳到/login-->    
                /wxConfig/**=roles[manager]
                /wechat/**=anon
                /exam/**=anon
                /playVideos/**=anon
                /**=authc  
                /graph/**=roles[admin]
                /webPage/**=roles[admin]
                /table/**=roles[admin]
            </value>    
        </property>    
    </bean> 

下面我開發說正題……

我先是想第一步從db中加載權限配置……

1.先改配置文件

<bean id="chainDefinitionSectionMetaSource"
        class="com.agnils.base.role.service.ChainDefinitionSectionMetaSource">
        <property name="filterChainDefinitions">
            <value>
                /sys/**=roles[admin]
                /user/**=roles[manager]
                /login=anon
                /logout=anon
            </value>
        </property>
    </bean>
    <!-- 配置shiro的過濾器工廠類,id- shiroFilter要和我們在web.xml中配置的過濾器一致 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 調用我們配置的權限管理器 -->
        <property name="securityManager" ref="securityManager" />
        <!-- 配置我們的登錄請求地址 -->
        <property name="loginUrl" value="/login" />
        <!-- 配置我們在登錄頁登錄成功后的跳轉地址,如果你訪問的是非/login地址,則跳到您訪問的地址 -->
        <property name="successUrl" value="/index" />
        <!-- 如果您請求的資源不再您的權限范圍,則跳轉到/403請求地址 -->
        <property name="unauthorizedUrl" value="/403" />
        <!-- 權限配置 -->
        <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource"></property>
    </bean>

 

2添加java類

  1 package com.agnils.base.role.service;
  2 
  3 import java.text.MessageFormat;
  4 import java.util.List;
  5 import java.util.Map;
  6 
  7 import org.apache.commons.lang.StringUtils;
  8 import org.apache.shiro.config.Ini;
  9 import org.apache.shiro.config.Ini.Section;
 10 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
 11 import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
 12 import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
 13 import org.apache.shiro.web.servlet.AbstractShiroFilter;
 14 import org.springframework.beans.factory.FactoryBean;
 15 import org.springframework.beans.factory.annotation.Autowired;
 16 
 17 import com.agnils.base.role.dao.ResourceDao;
 18 import com.agnils.base.role.entity.Resource;
 19 
 20 /**
 21  * 標題、簡要說明. <br>
 22  * 類詳細說明.
 23  * <p>
 24  * Copyright: Copyright (c) 2017-5-28 下午11:07:51
 25  * <p>
 26  * 
 27  * @author agnils@foxmail.com
 28  * @version 1.0.0
 29  */
 30 public class ChainDefinitionSectionMetaSource implements FactoryBean<Ini.Section> {
 31 
 32     @javax.annotation.Resource
 33     private ResourceDao resourceDao;
 34     @Autowired
 35     ShiroFilterFactoryBean shiroFilterFactoryBean;
 36 
 37     private String filterChainDefinitions;
 38     
 39 
 40     public static final String PREMISSION_STRING = "roles[\"{0}\"]";
 41 
 42     @Override
 43     public Section getObject() throws Exception {
 44 
 45         List<Resource> list = (List) resourceDao.findAll();
 46         Ini ini = new Ini();
 47         ini.load(filterChainDefinitions);
 48         Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
 49         for (Resource resource : list) {
 50             if (StringUtils.isNotBlank(resource.getValue()) && StringUtils.isNotBlank(resource.getPermission())) {
 51                 section.put(resource.getValue(), MessageFormat.format(PREMISSION_STRING, resource.getPermission()));
 52             }
 53         }
 54         return section;
 55     }
 56 
 57     @Override
 58     public Class<?> getObjectType() {
 59         return this.getClass();
 60     }
 61 
 62     @Override
 63     public boolean isSingleton() {
 64         return false;
 65     }
 66 
 67     public void setFilterChainDefinitions(String filterChainDefinitions) {
 68         this.filterChainDefinitions = filterChainDefinitions;
 69     }
 70     
 71     public void updatePermission() {  
 72           
 73         synchronized (shiroFilterFactoryBean) {  
 74   
 75             AbstractShiroFilter shiroFilter = null;  
 76   
 77             try {  
 78                 shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();  
 79             } catch (Exception e) {  
 80             }  
 81   
 82             // 獲取過濾管理器  
 83             PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter  
 84                     .getFilterChainResolver();  
 85             DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();  
 86   
 87             // 清空初始權限配置  
 88             manager.getFilterChains().clear();  
 89             shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();  
 90   
 91             // 重新構建生成  
 92             shiroFilterFactoryBean.setFilterChainDefinitions(filterChainDefinitions);  
 93             Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();  
 94   
 95             for (Map.Entry<String, String> entry : chains.entrySet()) {  
 96                 String url = entry.getKey();  
 97                 String chainDefinition = entry.getValue().trim().replace(" ", "");  
 98                 manager.createChain(url, chainDefinition);  
 99             }  
100   
101         }  
102     } 
103 
104 }
View Code

List<Resource> list = (List) resourceDao.findAll(); 這個就是從自己的權限表中取,動態添加,刪除,修改的權限。在這個我就不累贅說了……

按照第一步的配置這樣就可以從db中加載權限……但還是一個缺點就更改權限表中的數據時,還是重啟才能生效……

 

第二步,這是本博文的重點 動態加載權限

要想實現動態加載就要重寫ShiroFilterFactoryBean類代碼如下:

package com.agnils.base.sys.permissionRole.service;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.config.Ini;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.config.IniFilterChainResolverFactory;

import com.agnils.base.role.dao.ResourceDao;
import com.agnils.base.role.entity.Resource;
import com.agnils.base.user.entity.Permission;

/**
 * 標題、簡要說明. <br>
 * 類詳細說明.
 * <p>
 * Copyright: Copyright (c) 2017-6-3 下午9:51:02
 * <p>
 * 
 * @author agnils@foxmail.com
 * @version 1.0.0
 */
public class ShiroPermissionFactory extends ShiroFilterFactoryBean {

    public static final String PREMISSION_STRING = "roles[\"{0}\"]";

    // @javax.annotation.Resource
    // private PermissionService permissionService;

    @javax.annotation.Resource
    ResourceDao resourceDao;

    /** 記錄配置中的過濾鏈 */
    public static String filterChainDefinitions = "";//這個要和配置文件中的名稱要一樣

    /**
     * 初始化設置過濾鏈
     */
    @Override
    public void setFilterChainDefinitions(String definitions) {
        filterChainDefinitions = definitions;// 記錄配置的靜態過濾鏈
        Map<String, String> otherChains = new HashMap<String, String>();
        List<Resource> list = (List) resourceDao.findAll();
        for (Resource resource : list) {
            if (StringUtils.isNotBlank(resource.getValue()) && StringUtils.isNotBlank(resource.getPermission())) {
                otherChains.put(resource.getValue(), MessageFormat.format(PREMISSION_STRING, resource.getPermission()));
            }
        }
        otherChains.put("/**", "authc");
        // 加載配置默認的過濾鏈
        Ini ini = new Ini();
        ini.load(filterChainDefinitions);
        Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
        if (CollectionUtils.isEmpty(section)) {
            section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
        }
        // 加上數據庫中過濾鏈
        section.putAll(otherChains);
        setFilterChainDefinitionMap(section);

    }
}
View Code

Map<String, String> otherChains = new HashMap<String, String>();
List<Resource> list = (List) resourceDao.findAll();
for (Resource resource : list) {
if (StringUtils.isNotBlank(resource.getValue()) && StringUtils.isNotBlank(resource.getPermission())) {
otherChains.put(resource.getValue(), MessageFormat.format(PREMISSION_STRING, resource.getPermission()));
}
}
otherChains.put("/**", "authc");

這段代碼就是從db中取自己配置的權限,每個人的都不一樣,需要根據自己的情況修改

2.2 下面還要加一個FilterChainDefinitionsService類

package com.agnils.base.sys.permissionRole.service;

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.springframework.stereotype.Service;

/**
 * 標題、簡要說明. <br>
 * 類詳細說明.
 * <p>
 * Copyright: Copyright (c) 2017-6-3 下午9:49:01
 * <p>
 * 
 * @author agnils@foxmail.com
 * @version 1.0.0
 */
@Service
public class FilterChainDefinitionsService {

    @Resource
    private ShiroPermissionFactory permissionFactory;

    public void reloadFilterChains() {  
            synchronized (permissionFactory) {   //強制同步,控制線程安全  
                AbstractShiroFilter shiroFilter = null;  
      
                try {  
                    shiroFilter = (AbstractShiroFilter) permissionFactory.getObject();  
      
                    PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) shiroFilter  
                            .getFilterChainResolver();  
                    // 過濾管理器  
                    DefaultFilterChainManager manager = (DefaultFilterChainManager) resolver.getFilterChainManager();  
                    // 清除權限配置  
                    manager.getFilterChains().clear();  
                    permissionFactory.getFilterChainDefinitionMap().clear();  
                    // 重新設置權限  
                    permissionFactory.setFilterChainDefinitions(ShiroPermissionFactory.filterChainDefinitions);//傳入配置中的filterchains  
      
                    Map<String, String> chains = permissionFactory.getFilterChainDefinitionMap();  
                    //重新生成過濾鏈  
                    if (!CollectionUtils.isEmpty(chains)) {  
                        for (Map.Entry<String, String> chain : chains.entrySet()) {
                            manager.createChain(chain.getKey(), chain.getValue().replace(" ", ""));
                        }
                    }  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  
        }}
View Code

好代碼的都已完成,如果你做到這一步那你調reloadFilterChains()方法 。 在ShiroFilterFactoryBean類的section.putAll(otherChains);方法會報空指針異常……這個問題阻撓我好長時間。最后查了一下資料。問題出現在配置文件中,

2.3 更改配置文件

<bean id="myShiro" class="com.agnils.base.user.service.MyShiro">
        <!-- <property name="userService" ref="userService"/> -->
    </bean>
    <!-- 配置權限管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- ref對應我們寫的realm MyShiro -->
        <property name="realm" ref="myShiro" />
        <!-- 使用下面配置的緩存管理器 -->
        <property name="cacheManager" ref="cacheManager" />
    </bean>
    <!-- <bean id="chainDefinitionSectionMetaSource"
        class="com.agnils.base.role.service.ChainDefinitionSectionMetaSource">
        <property name="filterChainDefinitions">
            <value>
                /sys/**=roles[admin]
                /user/**=roles[manager]
                /login=anon
                /logout=anon
            </value>
        </property>
    </bean> -->
    <!-- 配置shiro的過濾器工廠類,id- shiroFilter要和我們在web.xml中配置的過濾器一致 -->
    <!-- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> -->
    <bean id="shiroFilter" class="com.agnils.base.sys.permissionRole.service.ShiroPermissionFactory">
        <!-- 調用我們配置的權限管理器 -->
        <property name="securityManager" ref="securityManager" />
        <!-- 配置我們的登錄請求地址 -->
        <property name="loginUrl" value="/login" />
        <!-- 配置我們在登錄頁登錄成功后的跳轉地址,如果你訪問的是非/login地址,則跳到您訪問的地址 -->
        <property name="successUrl" value="/index" />
        <!-- 如果您請求的資源不再您的權限范圍,則跳轉到/403請求地址 -->
        <property name="unauthorizedUrl" value="/403" />
        <!-- 權限配置 -->
        <!-- <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource"></property> -->
        <property name="filterChainDefinitions">
            <value>
                /sys/**=roles[admin]
                /user/**=roles[manager]
                /login=anon
                /logout=anon
            </value>
        </property>
    </bean>
View Code

寫了控制類 ReloadController

 1 package com.agnils.base.sys.permissionRole.web;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.stereotype.Controller;
 7 import org.springframework.web.bind.annotation.RequestMapping;
 8 
 9 import com.agnils.base.sys.permissionRole.service.FilterChainDefinitionsService;
10 
11 
12 /**
13  * 標題、簡要說明. <br>
14  * 類詳細說明.
15  * <p>
16  * Copyright: Copyright (c) 2017-6-3 下午10:44:27
17  * <p>
18  * @author agnils@foxmail.com
19  * @version 1.0.0
20  */
21 @Controller
22 public class ReloadController {
23 
24     @Autowired
25     FilterChainDefinitionsService filterChainDefinitionsService;
26 
27     @RequestMapping(value="/reloadRole")
28     public void reloadRole(HttpServletRequest request){
29         filterChainDefinitionsService.reloadFilterChains();
30     }
31 }
View Code

刪除,添加 db中的表權限自己測試通過,符合自己要求……

這個里我想說一句,本篇沒有全部的配置文件,但主要的關於shiro都在里面,本文了不給伸手黨寫的……因為每個人的表,不一樣所以要改的地方……

如遇到問題可以留言或都email聯系……


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM