本文结合了两位大佬的文章,自己实现了多个perm权限的配置 主要参考:SpringBoot-Shiro自定义过滤器实现配置多个权限 辅助参考:SpringBoot 使用Shiro权限框架自定义拦截器检查token失效
一.为什么要自定义过滤器
在项目开发过程中,安全对于后台管理很重要。shiro是一个比较常流行的安全框架,在项目中的权限配置会有各种不同的需求,例如有的url需要用户拥有多个权限中的一个权限就能够访问,这个就要自己编写拦截器(过滤器)的规则。
二.Shiro中的权限控制
shiro权限控制是在用户登录时会再realm中增加该用户的权限信息,在登录的时候会根据请求的url和相关的权限做映射。在用户请求具体url时,会根据url获得对应的权限,在到拦截器中做权限的校验。
我们看一下原本的两种写法。
fiterMap.put("/user/*","perms[user:add,root]");
fiterMap.put("/user/*","perms[root]");
上面的权限校验规则是PermissionsAuthorizationFilter 中,默认的权限校验规则。
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
Subject subject = this.getSubject(request, response);
String[] perms = (String[])((String[])mappedValue);
boolean isPermitted = true;
if (perms != null && perms.length > 0) {
if (perms.length == 1) {
if (!subject.isPermitted(perms[0])) {
isPermitted = false;
}
} else if (!subject.isPermittedAll(perms)) {
isPermitted = false;
}
}
return isPermitted;
}
从上面的代码可以看出,我们的配置会默认被强转为string类型的字符串数组。当只有一个权限时,会直接判断有没有该权限;当配置多个权限时,从下面的代码可以看出只用在请求url的用户拥有所有的权限时,才会返回true,否则就会被拒绝访问。
protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {
if (permissions != null && !permissions.isEmpty()) {
Iterator var3 = permissions.iterator();
while(var3.hasNext()) {
Permission p = (Permission)var3.next();
if (!this.isPermitted(p, info)) {
return false;
}
}
}
return true;
}
三.解决问题–实现拥有多个权限中的一个权限就能够访问
shiro源码只考虑了 权限的和 的问题没有通过配置解决权限的或的问题。因此为了满足业务需求,在自定义拦截器中需要重写PermissionsAuthorizationFilter的isAccessAllowed方法。为了满足 “和”和“或” 的不同权限配置的需求,对isAccessAllowed方法做如下修改:
自定义Shiro过滤器
RoleOrFilter.java
package com.company.gas.config;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class RoleOrFilter extends AuthorizationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
Subject subject = this.getSubject(request, response);
String[] perms = (String[]) ((String[]) mappedValue);
boolean isPermitted = true;
if (perms != null && perms.length > 0) {
if (perms.length == 1) {
if (!isOneOfPermitted(perms[0], subject)) {
isPermitted = false;
}
} else if (!isAllPermitted(perms,subject)) {
isPermitted = false;
}
}
return isPermitted;
}
private boolean isAllPermitted(String[] permStrArray, Subject subject) {
boolean isPermitted = true;
for (int index = 0, len = permStrArray.length; index < len; index++) {
if (!isOneOfPermitted(permStrArray[index], subject)) {
isPermitted = false;
}
}
return isPermitted;
}
private boolean isOneOfPermitted(String permStr, Subject subject) {
boolean isPermitted = false;
String[] permArr = permStr.split("\\|");
if (permArr.length > 0) {
for (int index = 0, len = permArr.length; index < len; index++) {
if (subject.isPermitted(permArr[index])) {
isPermitted = true;
}
}
}
return isPermitted;
}
}
** 2.ShiroConfig中shiroFilterFactoryBean方法中添加自定义过滤器**
@Bean(name = "bean")
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
RoleOrFilter roleOrFilter = new RoleOrFilter();
Map<String, Filter> myFilterMap = new HashMap<>();
myFilterMap.put("e-perms",roleOrFilter);
Map<String,String> filterMap = new LinkedHashMap<String, String>();
filterMap.put("/myIndex","anon");
filterMap.put("/myLogin","anon");
filterMap.put("/druid/**","anon");
filterMap.put("/facility/add","e-perms[2|3]");
filterMap.put("/**","authc");
bean.setUnauthorizedUrl("/myWeishouquan");
bean.setLoginUrl("/toLogin");
bean.setFilterChainDefinitionMap(filterMap);
bean.setFilters(myFilterMap);
return bean;
}
我们达到的效果:
- 保持“,”表示多个权限的并列关系,每个“,”分割的字符串可能是多个“或”权限的集合,再用“|”分割字符串,“|”需要转义。
修改后的权限控制:
fiterMap.put("/user/add","e-perms[user:add|root]");
fiterMap.put("/user/update","e-perms[user:update|root]");
结果 使得拥有user:add或者root权限的用户都能成功的访问 /user/add 接口了,同时兼容了shiro自带的权限检验规则
|