最近一朋友让我帮他做一个后台权限管理的项目。我就在我原来的项目加加改改但是还是不理想,查了不少资料也走了不了弯路。。。。。。

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不重启动态加载权限的更多相关文章

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

    一.前言 本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 . 按钮 .ur ...

  2. 基于xml 实现动态加载权限功能树列表---EFSFrame企业级开发架构

    在学习EFSFrame框架的过程中,感触最深的就是通过xml来实现前台与后台数据的交互,页面设计灵活,不用管后台如何写的,前台与后台的交互唯一的交互通道都是xml,在我们需要添加页面.添加规定的格式的 ...

  3. 6.0动态加载权限用PermissionGen

    ndroid 6.0 新增加了运行时的动态添加权限,在此介绍一个第三方库,PermissionGen,可以很方便简洁的增加 6.0权限 首先给大家上  PermissionGen 库地址:https: ...

  4. Asp.Net Core 项目实战之权限管理系统(8) 功能菜单的动态加载

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

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

    简述 可能大家都知道,php中有一个函数叫debug_backtrace,它可以回溯跟踪函数的调用信息,可以说是一个调试利器. 好,来复习一下 01 one(); 02 03 function one ...

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

    原文地址:http://www.cnblogs.com/melonblog/archive/2013/05/09/3062303.html 原文作者:豆浆油条 - melon 本文示例代码测试环境是W ...

  7. SpringSecurity动态加载用户角色权限实现登录及鉴权

    很多人觉得Spring Security实现登录验证很难,我最开始学习的时候也这样觉得.因为我好久都没看懂我该怎么样将自己写的用于接收用户名密码的Controller与Spring Security结 ...

  8. Spring与Shiro整合 加载权限表达式

    Spring与Shiro整合 加载权限表达式 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 如何加载权限表达式  我们在上章内容中画了一张图,里面有三个分项,用户 角色 权限: 那 ...

  9. vue-element-admin实战 | 第二篇: 最小改动接入后台实现根据权限动态加载菜单

    一. 前言 本篇基于 有来商城 youlai-mall微服务项目,通过对vue-element-admin的权限菜单模块理解个性定制其后台接口,实现对vue-element-admin工程几乎不做改动 ...

随机推荐

  1. 利用 Forcing InnoDB Recovery 特性解决 MySQL 重启失败的问题

    小明同学在本机上安装了 MySQL 5.7.17 配合项目进行开发,并且已经有了一部分重要数据.某天小明在开发的时候,需要出去一趟就直接把电脑关掉了,没有让 MySQL 正常关闭,重启 MySQL 的 ...

  2. 一个例子简要说明include和require的区别

    先编辑command.php文件 echo 'hello'.PHP_EOL; 然后编辑console.php文件 for($i=1;$i<=3;++$i){ require 'command1. ...

  3. JavaScript中screen对象的两个属性

    Screen 对象 Screen 对象包含有关客户端显示屏幕的信息. 这里说一下今天用到的两个属性:availHeigth,availWidth avaiHeigth返回显示屏幕的高度 (除 Wind ...

  4. 架构设计之Spring-Session分布式集群会话管理

    前言 通常在web开发中,回话管理是很重要的一部分,用于存储与用户相关的一些数据.对于JAVA开发者来说,项目中的session一般由Tomcat或者jetty容器来管理. 特点介绍 尽管使用特定的容 ...

  5. AIX误删除LV后如何进行现场保护和数据恢复工作

    在AIX环境下,若因维护误操作.存储mapping错误等,不小心将LV误删除,这种损失通常是巨大的.删除后的不当保护及恢复操作可能使数据无法恢复,也可能增加处理的时间与算法复杂度.如何有效保护现场,并 ...

  6. Postmark介绍

    一. 引言 Postmark是由著名的NAS提供商NetApp开发,用来测试其产品的后端存储性能. Postmark主要用于测试文件系统在邮件系统或电子商务系统中性能,这类应用的特点是:需要频繁.大量 ...

  7. mui开发app之webview是什么

    WebView(网络视图)能加载显示网页,可以将其视为一个浏览器,webview被封装在html5+,plus对象中,底层由java,OC实现. 先来谈谈我对webview的理解: 使用mui开发的a ...

  8. unity 本地帮助文档 慢

    unity ,打开本地帮助文档时,有时会加载很慢,主要原因是网页里嵌入了访问google的代码.解决办法:打开本地hosts文件,里面加入"127.0.0.1 fonts.googleapi ...

  9. MYSQL设置远程账户登陆总结

    为了给MYSQL用户设置远程连接权限,经历的种种错误总结 ERROR 2003 (HY00 原因是MySQL考虑到安全因素,默认配置只让从本地登录 打开 /etc/mysql/my.cnf 文件,找到 ...

  10. springmvc 导出excel

    1.pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...