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 [email protected]
 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 }

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 [email protected]
 * @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);

    }
}

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 [email protected]
 * @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();
                }
            }
        }}

好代码的都已完成,如果你做到这一步那你调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>

写了控制类 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 [email protected]
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 }

删除,添加 db中的表权限自己测试通过,符合自己要求……

这个里我想说一句,本篇没有全部的配置文件,但主要的关于shiro都在里面,本文了不给伸手党写的……因为每个人的表,不一样所以要改的地方……

如遇到问题可以留言或都email联系……

时间: 2024-12-29 23:50:21

shiro不重启动态加载权限的相关文章

SpringBoot集成Shiro 实现动态加载权限

一.前言 本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 . 按钮 .uri 权限后,后端动态分配权限,用户无需在页面重新登录才能获取最新权限,一切权限动态加载,灵活配置 基本环境 spring-boot 2.1.7 mybatis-plus 2.1.0 mysql 5.7.24 redis 5.0.5 温馨小提示:案例demo源码附文章末尾,有需要的小伙伴们可参考哦 ~

Android APP启动页面动态加载全部权限

一.写在前面 6.0以上动态加载权限加载的是,需要用户手动赋予的权限( Dangerous Permissions),只有这些,其他权限不用加载 所属权限组 权限日历 READ_CALENDAR日历 WRITE_CALENDAR相机 CAMERA联系人 READ_CONTACTS联系人 WRITE_CONTACTS联系人 GET_ACCOUNTS位置 ACCESS_FINE_LOCATION位置 ACCESS_COARSE_LOCATION麦克风 RECORD_AUDIO电话 READ_PHON

__利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载

利用PHP的debug_backtrace函数,实现PHP文件权限管理.动态加载 简述 可能大家都知道,php中有一个函数叫debug_backtrace,它可以回溯跟踪函数的调用信息,可以说是一个调试利器. 好,来复习一下.view source?01    one();02     03    function one() {04        two();05    }06     07    function two() {08        three();09    }10    

利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载

简述 可能大家都知道,php中有一个函数叫debug_backtrace,它可以回溯跟踪函数的调用信息,可以说是一个调试利器. 好,来复习一下 01 one(); 02 03 function one() { 04 two(); 05 } 06 07 function two() { 08 three(); 09 } 10 11 function three() { 12 print_r( debug_backtrace() ); 13 } 14 15 /* 16 输出: 17 Array 18

(转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】

原文地址:http://www.cnblogs.com/melonblog/archive/2013/05/09/3062303.html 原文作者:豆浆油条 - melon 本文示例代码测试环境是Windows下的APMServ(PHP5.2.6) 简述 可能大家都知道,php中有一个函数叫debug_backtrace,它可以回溯跟踪函数的调用信息,可以说是一个调试利器. 好,来复习一下. one(); function one() { two(); } function two() { t

7. 反射技术:其实就是动态加载一个指定的类

反射技术:其实就是动态加载一个指定的类,并获取该类中的所有的内容.而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员.简单说:反射技术可以对一个类进行解剖. 反射的好处:大大的增强了程序的扩展性. 反射的基本步骤: 1.获得Class对象,就是获取到指定的名称的字节码文件对象. 2.实例化对象,获得类的属性.方法或构造函数. 3.访问属性.调用方法.调用构造函数创建对象. 获取这个Class对象,有三种方式: 1:通过每个对象都具备的方法getClass来获取.

jquery easyui datagrid 动态 加载列

实现方式: 首先根据输入的sql语句获得相关的列名称返回给前台,然后在datagrid中动态加载列,接着根据查询条件(包括sql语句)获取相关的记录返回给前台用于填充datagrid.从而实现类似oracle web版的sql查询. 前台主要js为: Js代码   function sqlSearch(){ var sqlStatement = $.trim($("#sqlStatementId").val()); if(sqlStatement == null || sqlState

Java中动态加载jar文件和class文件

概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下的jar文件以及classes目录下的class文件,另外像spring这类框架,也可以根据指定的路径扫描并加载指定的类文件,这个技术可以实现一个容器,容纳各类不同的子应用. Java类由于需要加载和编译字节码,动态加载class文件较为麻烦,不像C加载动态链接库只要一个文件名就可以搞定,但JDK仍提供了一整套方法来动态加载jar文件和class文件. 动态加载jar文件 // 系统类库路径 File libPath =

【转】Android类动态加载技术

http://www.blogjava.net/zh-weir/archive/2011/10/29/362294.html Android应用开发在一般情况下,常规的开发方式和代码架构就能满足我们的普通需求.但是有些特殊问题,常常引发我们进一步的沉思.我们从沉思中产生顿悟,从而产生新的技术形式. 如何开发一个可以自定义控件的Android应用?就像eclipse一样,可以动态加载插件:如何让Android应用执行服务器上的不可预知的代码?如何对Android应用加密,而只在执行时自解密,从而防