Shiro自定义拦截器实现权限或
阅读Shiro的文档可以知道,Shiro提供的多个权限相关的验证方法只有and关系,而没有提供or的校验方法,也就是说并不支持拥有多个权限中的某一个就验证成功的情景。
Shiro的AccessControlFilter提供了访问控制的基础功能,其中提供的isAccessAllowed方法的返回值表示了是否允许访问。打开他的继承关系可以看到:
AuthenticationFilter和AuthorizationFilter下的实现类都对这个方法提供了实现。前者是认证过滤器,后者是授权过滤器。显然我们应该关注后者的实现方法。我们查看后者PermissionsAuthorizationFilter的实现:
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
Subject subject = getSubject(request, response);
String[] perms = (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;
}
其中isAccessAllowed方法的参数mappedValue就是[urls]配置中拦截器参数部分,也就是我们配置的权限表达式的值,要实现多个权限下“或”的匹配规则,我们只需要自定义一个过滤器,去仿照着重写这个方法即可,我们对应shiro本身规则的“,”,增加“|”来表示or,同时考虑保留shiro本身支持的“,”逗号表示匹配多个权限and的规则,代码如下:
public class CustomAuthorizationFilter extends PermissionsAuthorizationFilter{
//保留shiro原有的“,”分隔and的校验规则,新增“|”分隔的规则
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
Subject subject = this.getSubject(request, response);
String[] perms = (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;
}
//权限表达式","分隔,and的校验规则
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;
}
//权限表达式"|"分隔,or的校验规则
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;
}
}
最后还要将自定义的过滤器加入到shiroFilter中:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" depends-on="orFilter">
<property name="securityManager" ref="securityManager" />
<property name="filters">
<map>
<entry key="perms" value-ref="orFilter"/>
</map>
</property>
</bean>
<!-- 自定义的过滤器 -->
<bean id="orFilter" class="com.default.CustomAuthorizationFilter" />
map中key的值perms不可以更改,这样就实现了满足多个权限中的一个就验证通过的需求。