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类
package com.agnils.base.role.service; import java.text.MessageFormat;
import java.util.List;
import java.util.Map; import org.apache.commons.lang.StringUtils;
import org.apache.shiro.config.Ini;
import org.apache.shiro.config.Ini.Section;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
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.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired; import com.agnils.base.role.dao.ResourceDao;
import com.agnils.base.role.entity.Resource; /**
* 标题、简要说明. <br>
* 类详细说明.
* <p>
* Copyright: Copyright (c) 2017-5-28 下午11:07:51
* <p>
*
* @author agnils@foxmail.com
* @version 1.0.0
*/
public class ChainDefinitionSectionMetaSource implements FactoryBean<Ini.Section> { @javax.annotation.Resource
private ResourceDao resourceDao;
@Autowired
ShiroFilterFactoryBean shiroFilterFactoryBean; private String filterChainDefinitions; public static final String PREMISSION_STRING = "roles[\"{0}\"]"; @Override
public Section getObject() throws Exception { List<Resource> list = (List) resourceDao.findAll();
Ini ini = new Ini();
ini.load(filterChainDefinitions);
Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
for (Resource resource : list) {
if (StringUtils.isNotBlank(resource.getValue()) && StringUtils.isNotBlank(resource.getPermission())) {
section.put(resource.getValue(), MessageFormat.format(PREMISSION_STRING, resource.getPermission()));
}
}
return section;
} @Override
public Class<?> getObjectType() {
return this.getClass();
} @Override
public boolean isSingleton() {
return false;
} public void setFilterChainDefinitions(String filterChainDefinitions) {
this.filterChainDefinitions = filterChainDefinitions;
} public void updatePermission() { synchronized (shiroFilterFactoryBean) { AbstractShiroFilter shiroFilter = null; try {
shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
} catch (Exception e) {
} // 获取过滤管理器
PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
.getFilterChainResolver();
DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager(); // 清空初始权限配置
manager.getFilterChains().clear();
shiroFilterFactoryBean.getFilterChainDefinitionMap().clear(); // 重新构建生成
shiroFilterFactoryBean.setFilterChainDefinitions(filterChainDefinitions);
Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap(); for (Map.Entry<String, String> entry : chains.entrySet()) {
String url = entry.getKey();
String chainDefinition = entry.getValue().trim().replace(" ", "");
manager.createChain(url, chainDefinition);
} }
} }
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); }
}
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();
}
}
}}
好代码的都已完成,如果你做到这一步那你调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
package com.agnils.base.sys.permissionRole.web; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import com.agnils.base.sys.permissionRole.service.FilterChainDefinitionsService; /**
* 标题、简要说明. <br>
* 类详细说明.
* <p>
* Copyright: Copyright (c) 2017-6-3 下午10:44:27
* <p>
* @author agnils@foxmail.com
* @version 1.0.0
*/
@Controller
public class ReloadController { @Autowired
FilterChainDefinitionsService filterChainDefinitionsService; @RequestMapping(value="/reloadRole")
public void reloadRole(HttpServletRequest request){
filterChainDefinitionsService.reloadFilterChains();
}
}
删除,添加 db中的表权限自己测试通过,符合自己要求……
这个里我想说一句,本篇没有全部的配置文件,但主要的关于shiro都在里面,本文了不给伸手党写的……因为每个人的表,不一样所以要改的地方……
如遇到问题可以留言或都email联系……
shiro不重启动态加载权限的更多相关文章
- SpringBoot集成Shiro 实现动态加载权限
一.前言 本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 . 按钮 .ur ...
- 基于xml 实现动态加载权限功能树列表---EFSFrame企业级开发架构
在学习EFSFrame框架的过程中,感触最深的就是通过xml来实现前台与后台数据的交互,页面设计灵活,不用管后台如何写的,前台与后台的交互唯一的交互通道都是xml,在我们需要添加页面.添加规定的格式的 ...
- 6.0动态加载权限用PermissionGen
ndroid 6.0 新增加了运行时的动态添加权限,在此介绍一个第三方库,PermissionGen,可以很方便简洁的增加 6.0权限 首先给大家上 PermissionGen 库地址:https: ...
- Asp.Net Core 项目实战之权限管理系统(8) 功能菜单的动态加载
0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...
- 利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载
简述 可能大家都知道,php中有一个函数叫debug_backtrace,它可以回溯跟踪函数的调用信息,可以说是一个调试利器. 好,来复习一下 01 one(); 02 03 function one ...
- (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】
原文地址:http://www.cnblogs.com/melonblog/archive/2013/05/09/3062303.html 原文作者:豆浆油条 - melon 本文示例代码测试环境是W ...
- SpringSecurity动态加载用户角色权限实现登录及鉴权
很多人觉得Spring Security实现登录验证很难,我最开始学习的时候也这样觉得.因为我好久都没看懂我该怎么样将自己写的用于接收用户名密码的Controller与Spring Security结 ...
- Spring与Shiro整合 加载权限表达式
Spring与Shiro整合 加载权限表达式 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 如何加载权限表达式 我们在上章内容中画了一张图,里面有三个分项,用户 角色 权限: 那 ...
- vue-element-admin实战 | 第二篇: 最小改动接入后台实现根据权限动态加载菜单
一. 前言 本篇基于 有来商城 youlai-mall微服务项目,通过对vue-element-admin的权限菜单模块理解个性定制其后台接口,实现对vue-element-admin工程几乎不做改动 ...
随机推荐
- sql中的for xml path() 实现字符串拼接
通常我们需要在sql中拼接字符串 ,可以用for xml path() 来进行拼接,如下实例. 同时未去掉最后一个逗号可以用LEFT函数来实现. ) AS UserName FRO ...
- webpack 打包成功,但是css不起作用
问题: webpack 打包成功,但是css不起作用 问题分析/解决: 原因有以下几种 使用了webpack2的语法规则不正确; webpack2要求必须写-loader; 可能是只写了css-loa ...
- iptables配置详解
iptables主要参数 -A 向规则链中添加一条规则,默认被添加到末尾 -T指定要操作的表,默认是filter -D从规则链中删除规则,可以指定序号或者匹配的规则来删除 -R进行规则替换 -I插入一 ...
- nodejs + nginx + ECS阿里云服务器环境设置
nodejs + nginx + ECS阿里云服务器环境设置 部署 nodejs ECS 基于 CentOS7.2 详细步骤:click 部署 nginx 安装 添加Nginx软件库: [root@l ...
- 快速认识HTML及一般标签
HTML(Hype Text Language,超文本标记语言) <html >--开始标签 <head> 网页控制信息 <title>网页标题</title ...
- ASP.NET MVC4 微信公众号开发之网页授权(二):通过公众号AppID(应用ID)和AppSecret(应用密钥)取得网页授权openid
ASP.NET MVC4 微信公众号开发之网页授权(一):搭建基础环境 通过了上一篇文章我们已经搭建好了基础开发大环境,现在打开开发环境这里我用的是 vs2013,通过如下方式: 拼接请求链接重定向到 ...
- CF #344 D. Messenger KMP/Z
题目链接:http://codeforces.com/problemset/problem/631/D 给定两个压缩形式的字符串,如a3b5a4k7这样的形式 问A在B中出现次数. 分类讨论,如果A是 ...
- C#网络程序设计(2)Socket基础编程
本节介绍如何使用基础Socket实现TCP通信. (1)Socket详细介绍: Socket的英文原义是"孔"或"插座".通常称作"套 ...
- Linux字符设备与块设备的区别与比较
Linux中I/O设备分为两类:块设备和字符设备.两种设备本身没有严格限制,但是,基于不同的功能进行了分类. (1) 字符设备:提供连续的数据流,应用程序可以顺序读取,通常不支持随机存取.相反,此类设 ...
- poj3320尺取法
Jessica's a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is co ...