在之前 Shiro 集成 Spring 这一章中我们简单使用了 shiroFilter 中的 filterChainDefinitions 来做 认证 和 授权 的拦截,其实还有许多过滤器,可以做各种各样的拦截,并且 Shiro 还提供了接口来让我们自定义过滤器。
例:/admins/**=anon,没有参数,表示可以匿名使用。
例:/admins/user/**=authc,没有参数,表示需要认证(登录)才能使用。
例:/admins/user/**=authcBasic,没有参数,表示 httpBasic 认证。
例:/admins/user/**=user ,没有参数,表示必须存在用户(不一定已通过认证),只要曾被 Shiro 记住过登录状态的用户就可以正常发起请求,比如 rememberMe)。
例:/logout=logout,没有参数,注销当前登陆用户,成功后会重定向地址到 /。
例:/admins/user/**=roles[admin],参数可以写多个,用逗号分割,当有多个参数时,例如 admins/user/**=roles[admin, guest],每个参数通过才算通过,相当于 hasAllRoles() 方法。
例:/admins/user/**=perms[user:add:*],参数可以写多个,用逗号分割,如:/admins/user/**=perms[user:add:*, user:modify:*],当有多个参数时必须每个参数都通过才通过,想当于 isPermitedAll() 方法。
例: /admins/user/**=port[8081],单个参数,当请求的 url 的端口不是 8081 时重定向到 schemal://hostName:8081?queryString, 也就是说,除了端口,其他东西都会保留。
例:/admins/user/**=rest[user],根据请求的方法,相当于 /admins/user/**=perms[user:method],其中method为post,get,delete等。
例:/admins/user/**=ssl 没有参数,表示安全的 url 请求,协议为 https,其实也等同于 /admin/user/**=port[443],即重定向到 443 端口。
以 roles 过滤器为例:/admin/page1= roles["admin, user"] ,表示 /admin/page1 这个页面必须需要用户同时具备 admin 与 user 角色才可访问。
我们开发一个自定义的过滤器,判定需要 admin 或 user 可访问。
package im.zhaojun.filter;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class AnyRolesFilter extends AuthorizationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
Subject subject = this.getSubject(request, response);
String[] rolesArray = (String[]) ((String[]) mappedValue);
if (rolesArray != null && rolesArray.length != 0) {
for (String role : rolesArray) {
if (subject.hasRole(role)) {
return true;
}
}
} else {
return true;
}
return false;
}
}注:这里用到了 ServletRequest 和 ServletResponse 类,所以还需要导入相应的库:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>然后将其配置到 IOC 容器中:
<bean id="anyRolesFilter" class="im.zhaojun.filter.AnyRolesFilter"/>最后为其分配别名,并添加到过滤器链中:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 略 -->
<property name="filterChainDefinitions">
<value>
/login.jsp = anon
/login = anon
/user.jsp = anyRoles[user, admin]
/userList.jsp = perms[select:delete]
/logout = logout
/** = authc
</value>
</property>
<property name="filters">
<map>
<entry key="anyRoles" value-ref="anyRolesFilter"/>
</map>
</property>
</bean>我们分别将 /user.jsp 设为 roles[user, admin] 和 anyRoles[user, admin]。
目前 Relam 中的用户 zhao - 123456 仅具备 user 角色,所以可以分别测试出,anyRoles 过滤的页面可以正常访问,而 roles 过滤器的内容因未同时具备 user 与 admin 角色而被拦截,跳转到未授权页面。
上面的示例中,我们还用到了 ** 做通配符,其实还有几个通配符:
?:匹配一个字符,如 /admin? 可以匹配 /admin1、/admin2,但不能匹配 /admin。
*:匹配零个或一个或多个字符,如 /admin* 可以匹配 /admin、/admin1、/admin123,但不能匹配 /admin/123。
**:匹配零个或多个路径,如 /admin/** 可以匹配 /admin、/admin/a/b/c。
本章代码地址 : https://github.com/zhaojun1998/Premission-Study/tree/master/Permission-Shiro-07/