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工程几乎不做改动 ...
随机推荐
- druid查询
查询是发送HTTP请求到,Broker, Historical或者Realtime节点.查询的JSON表达和每种节点类型公开相同的查询接口. Queries are made using an HTT ...
- 【局域网聊天客户端篇】基于socket与Qt
前言 暑假把linux下的高级编程和网络编程学习了一遍,学习很重要,但是也得有个练手的地方,所以必须做做项目来认识下自己所学习的知识. 能够找到小伙伴一起做项目也是一件很快乐的事情的,很幸运的有两个小 ...
- Linux学习---vi/vim命令
Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用. 所以本文直接用Vim编辑器 基本上 vi/vim 共分为三种模式,分别是命令模式( ...
- Linux - atexit()(注册终止)函数
进程终⽌的⽅式有8种,前5种为正常终⽌,后三种为异常终⽌: 1. 从main函数返回: 2 .调⽤exit函数:3 .调⽤_exit或_Exit:4 .最后⼀个线程从启动例程返回:5 .最后⼀个线程调 ...
- [编织消息框架][消息服务]jmx
JMX(Java Management Extensions,即Java管理扩展)是一个为应用程序.设备.系统等植入管理功能的框架,使用的是RMI技术. 比较经典的应用jdk bin目录下 jcons ...
- 烧录口被初始化为普通IO
烧录口被初始化为普通IO后如果复位端没有的烧录口会导致不能识别烧录器不能下载与调试,因为程序一开始就把端口初始化了,烧录器不能识别,添加复位端口到烧录器(前提是你的烧录器有复位端). 有了复位段之后, ...
- 【从无到有】JavaScript新手教程——1.简介、变量和运算符
今天带大家来学习一下在网页制作过程中很常用的JavaScript(简称JS). 一.JS的作用: 表单验证,减轻服务端的压力 添加页面动画效果 动态更改页面内容 Ajax网络请求 二.[使用JS的 ...
- BackgroundWorker的DoWork方法中发生异常无法传递到RunWorkedCompleted方法
在使用C#的BackgroundWorker时需要在UI界面上显示DoWork中发生的异常,但怎么调试都无法跳转到界面上,异常也不会传递到RunWorkerCompleted方法中(e.Error为空 ...
- office web apps 部署-搭建域控服务器
开始第一条先说注意事项:我所配置的环境是用了三台2012server虚拟机,三台虚拟机必须要加下域控,而且登录操作的时候必须以域账号登录,否则测试不通过!在笔记本上搭建了两个虚拟机(window se ...
- 前端工作日常爬坑之——单页面微信开发Jssdk相关,以及jssdk图片直传自己服务器的实现。
日常爬坑 遇到的情况大致说明: 项目基于Vue2全家桶实现,vue-router控制前端路由,路由模式是History(主要是领导追求太高,觉得hash带#号太丑,然后遇到了小坑...),主要是服务于 ...