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工程几乎不做改动 ...
随机推荐
- php生成器使用总结
一般我们在迭代一组数据的时候,需要创建一个数据,如果数组很大,则会消耗很大性能,甚至造成内存不足抛出error比如: //Fatal error: Allowed memory size of 134 ...
- WPF中button按钮同时点击多次触发click解决方法
DateTime lastClick = DateTime.Now; object obj = new object(); ; private void Button_Click(object sen ...
- C#,VB.NET 如何将Excel转换为Text
在工作中,有时我们需要转换文档的格式,之前已经跟大家介绍过了如何将Excel转换为PDF.今天将与大家分享如何将Excel转换为Text.这次我使用的依然是免费版的Spire.XLS for .NET ...
- 【Java 并发】详解 ThreadPoolExecutor
前言 线程池是并发中一项常用的优化方法,通过对线程复用,减少线程的创建,降低资源消耗,提高程序响应速度.在 Java 中我们一般通过 Exectuors 提供的工厂方法来创建线程池,但是线程池的最终实 ...
- Linux防火墙配置—允许转发
一.实验目标 在上一次"Linux基础网络搭建实验"中,内.外网虚拟机之所以能Ping通,是因为暂时关闭了防火墙,然而现实中这样操作显然存在很大的安全隐患,所以本次实验在上次实验的 ...
- JS中Object常用的一些属性和方法
1⃣️属性 刚接触prototype.constructor.proto这三个玩意儿的时候,是不是有点儿傻傻分不清楚的感觉?下面来简单的说下... 举
- html常用的知识点以及混合框架
html中: <hr/> 在页面中创建水平线 例如: <p> p标签是定义段落 > alt 作为可预备可替换信息,在无法加载图片时显示文字信息 定义htm ...
- 浅谈移动端rem的用法
一 什么是rem? “font size of the root element 这是w3c的定义 也就是说是相对于根节点(html节点)的字体大小的单位. 目前主流的浏览器基本都支持rem这个单位, ...
- Codeforces Round #410 (Div. 2)D题
D. Mike and distribution time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- input file图片上传预览效果
两种方法,方法一: js代码: //头像上传预览 $("#up").change(function() { var $file = $(this); var fileObj = $ ...