Shiro教程(十)Shiro 权限动态加载与配置精细讲解
Shiro + SSM(框架) + Freemarker(jsp)讲解的权限控制Demo,还不赶快去下载?
Shiro 是一个很完美的权限控制框架,一般我们会采用 shiro 的标签,在页面判断,从而来判断一些Button
,Link Tag
的显示与否,但是仅仅这样判断是不够的,如果用户知道链接,这就一点用都没有。所以我们后台还要有一层判断。这样才安全。今天来说说 Shiro 后台判断的这点事。
shiro标签讲解:
Freemarker 使用Shiro
标签的介绍:https://www.sojson.com/blog/143.html
JSP 使用Shiro
标签的介绍:https://www.sojson.com/blog/144.html
shiro一般是这样配置。
<property name="filterChainDefinitions" >
<value>
/** = anon
/page/login.jsp = anon
/page/register/* = anon
/page/index.jsp = authc
/page/addItem* = authc,roles[数据管理员]
/page/file* = authc,roleOR[普通用户,数据管理员]
/page/listItems* = authc,roleOR[数据管理员,普通用户]
/page/showItem* = authc,roleOR[数据管理员,普通用户]
/page/updateItem*=authc,roles[数据管理员]
</value>
</property>
这样配置有什么问题?
shiro 加载配置,或者说校验配置,是从上而下的,也就是向上面的配置,其实是有问题的。可能不仔细看你没看出来,/** = anon
,如果把这个配置在第一行,其实下面的配置都没用。因为是从上往下去匹配,只要匹配中了,就不匹配了,这个是重点,所以要有序。
其次,我们知道,这样配置有一个问题,就是维护起来费劲,它不如单独的配置文件,比如我们常用properties
配置文件来配置一些经常修改的值。如:jdbc.properties
会配置一些数据库的链接,帐号、密码等。
说到这里,有的同学就会想,那么我们就用 properties
?
properties
我们来看看有什么问题?
用 properties
配置,其实是没问题,问题就出在读取 properties
配置上。我们一般读取,或者说常用读取properties
配置文件,都是用相对应的 Java JDK 自带提供java.util.Properties
工具类,我们可以看到这个工具类的情况。
public class Properties extends Hashtable<Object,Object> {
//Do some thing
}
它继承了 Hashtable
,这就是出现了一个问题,Hashtable
是无序的。这就是关键点。
Shiro 权限拦截动态配置方案
1.重写java.util.Properties
工具类 ,继承 LinkedHashMap<K, V>()
,LinkedHashMap()
2.自己写一个读取文件的工具类也可以解决。
我的实现是用ini配置文件,自己写了一个读取的工具类,已经封装好,欲知详情或者下载请点击:https://www.sojson.com/blog/139.html
里面有工具类的下载,本站的实现,以及本站发布的开源Demo项目:SpringMVC + Mybatis + Shiro + Redis 。
这个 Demo 里的配置文件:
[base_auth]
/u/**=anon
/user/**=simple,login
/js/**=anon
/css/**=anon
/open/**=anon
#不用校验地址是否有权限
/permission/selectPermissionById.shtml=simple,login
/member/onlineDetails/**=simple,login
/role/mypermission.shtml=simple,login
/role/getPermissionTree.shtml=simple,login
/role/selectRoleByUserId.shtml=simple,login
#需要根据地址校验有无权限
/permission/**=simple,login,permission
/role/**=simple,login,permission
/member/**=simple,login,permission
/**=simple,login
配置文件加载类:
package com.sojson.core.shiro.service.impl;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
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.core.io.ClassPathResource;
import com.sojson.common.utils.LoggerUtils;
import com.sojson.core.config.INI4j;
import com.sojson.core.shiro.service.ShiroManager;
/**
*
* 开发公司:SOJSON在线工具 <p>
* 版权所有:© www.sojson.com<p>
* 博客地址:https://www.sojson.com/blog/ <p>
* <p>
*
* 动态加载权限 Service
*
* <p>
*
* 区分 责任人 日期 说明<br/>
* 创建 周柏成 2016年6月2日 <br/>
*
* @author zhou-baicheng
* @email so@sojson.com
* @version 1.0,2016年6月2日 <br/>
*
*/
public class ShiroManagerImpl implements ShiroManager {
// 注意/r/n前不能有空格
private static final String CRLF = "\r\n";
@Resource
private ShiroFilterFactoryBean shiroFilterFactoryBean;
@Override
public String loadFilterChainDefinitions() {
StringBuffer sb = new StringBuffer();
sb.append(getFixedAuthRule());//固定权限,采用读取配置文件
return sb.toString();
}
/**
* 从配额文件获取固定权限验证规则串
*/
private String getFixedAuthRule(){
String fileName = "shiro_base_auth.ini";
ClassPathResource cp = new ClassPathResource(fileName);
INI4j ini = null;
try {
ini = new INI4j(cp.getFile());
} catch (IOException e) {
LoggerUtils.fmtError(getClass(), e, "加载文件出错。file:[%s]", fileName);
}
String section = "base_auth";
Set<String> keys = ini.get(section).keySet();
StringBuffer sb = new StringBuffer();
for (String key : keys) {
String value = ini.get(section, key);
sb.append(key).append(" = ")
.append(value).append(CRLF);
}
return sb.toString();
}
// 此方法加同步锁
@Override
public synchronized void reCreateFilterChains() {
// ShiroFilterFactoryBean shiroFilterFactoryBean = (ShiroFilterFactoryBean) SpringContextUtil.getBean("shiroFilterFactoryBean");
AbstractShiroFilter shiroFilter = null;
try {
shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
} catch (Exception e) {
LoggerUtils.error(getClass(),"getShiroFilter from shiroFilterFactoryBean error!", e);
throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
}
PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
.getFilterChainResolver();
DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver
.getFilterChainManager();
// 清空老的权限控制
manager.getFilterChains().clear();
shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
shiroFilterFactoryBean.setFilterChainDefinitions(loadFilterChainDefinitions());
// 重新构建生成
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);
}
}
public void setShiroFilterFactoryBean(
ShiroFilterFactoryBean shiroFilterFactoryBean) {
this.shiroFilterFactoryBean = shiroFilterFactoryBean;
}
}
具体请查看:
本站发布的开源Demo项目:SpringMVC + Mybatis + Shiro + Redis 。
Github下载:https://github.com/baichengzhou/SpringMVC-Mybatis-shiro
版权所属:SO JSON在线解析
原文地址:https://www.sojson.com/blog/148.html
转载时必须以链接形式注明原始出处及本声明。
如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。