Shiro中的Filters定义
下图为Shiro中所有的Filter定义
可以看出,基本上分为两大类的Filter,一个是PathMatchingFilter
,另一个就是LogoutFilter
。LogoutFilter
作为登出Filter,暂不介绍。
所有的filter,全部是OncePerRequestFilter的子类,OncePerRequestFilter作为Filter中doFilter实现的主要类,主要内容在其子类的doFilterInternal中实现。
首先,需要知道Shiro的启动过程和加载顺序,当前以Spring+Shiro+CAS进行配置。
1. web.xml配置
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
使用spring进行托管Shiro Filter
2 Shiro配置
<!-- 配置CAS Filter,用于CAS校验用户是否登录与用户权限 -->
<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
<property name="failureUrl" value="/shiro/error"/>
</bean>
<!-- Shiro Filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl"
value="https://cas_server_url/cas/login?service=http://localhost:8080/cas"/>
<property name="filters">
<map>
<entry key="casFilter" value-ref="casFilter"/>
<entry key="role" value-ref="roleFilter"/>
</map>
</property>
<property name="filterChainDefinitions">
<value>
<!-- 用于控制用户登录验证 -->
/cas = casFilter
<!-- 用于控制用户权限验证 -->
/** = role
</value>
</property>
</bean>
<bean id="roleRealm" class="org.ihsxin.test.shiro.core.realm.RoleRealm">
<property name="casServerUrlPrefix" value="https://cas_server_url/cas/"/>
<property name="casService" value="http://localhost:8080/cas"/>
<property name="roleManager">
<bean class="org.ihsxin.test.shiro.core.role.impl.RoleManagerImpl">
<property name="userRoleMapper" ref="userRoleMapper"/>
</bean>
</property>
</bean>
<bean id="memoryConstrainedCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"/>
<bean id="memorySessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"/>
<bean id="defaultSessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="cacheManager" ref="memoryConstrainedCacheManager"/>
<property name="sessionDAO" ref="memorySessionDAO"/>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="roleRealm"/>
<property name="subjectFactory" ref="casSubjectFactory"/>
<property name="cacheManager" ref="memoryConstrainedCacheManager"/>
<property name="sessionManager" ref="defaultSessionManager"/>
</bean>
<bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
<property name="arguments" ref="securityManager"/>
</bean>
首先,需要明白Shiro框架的几大概念:
1.1 SecurityManager
1.2 Subject
1.3 Realm
现在,以执行顺序方式,追踪记录一层请求的代码路由顺序。
1. Spring Shiro
PathMatchingFilter
作为大的父类,主要的一个功能,就是匹配操作符及操作路径,如果符合这个路径,才执行自身方法。
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
// 如果当前的适用的Path没有,默认允许,直接返回true
if (this.appliedPaths == null || this.appliedPaths.isEmpty()) {
if (log.isTraceEnabled()) {
log.trace("appliedPaths property is null or empty. This Filter will passthrough immediately.");
}
return true;
}
// 遍历自身的Apply path,如果匹配,则通过执行isFilterChainContinued方法
for (String path : this.appliedPaths.keySet()) {
// If the path does match, then pass on to the subclass implementation for specific checks
//(first match 'wins'):
if (pathsMatch(path, request)) {
log.trace("Current requestURI matches pattern '{}'. Determining filter chain execution...", path);
Object config = this.appliedPaths.get(path);
return isFilterChainContinued(request, response, path, config);
}
}
//no path matched, allow the request to go through:
return true;
}
/**
* Simple method to abstract out logic from the preHandle implementation - it was getting a bit unruly.
*
* @since 1.2
*/
@SuppressWarnings({"JavaDoc"})
private boolean isFilterChainContinued(ServletRequest request, ServletResponse response,
String path, Object pathConfig) throws Exception {
if (isEnabled(request, response, path, pathConfig)) { //isEnabled check added in 1.2
if (log.isTraceEnabled()) {
log.trace("Filter '{}' is enabled for the current request under path '{}' with config [{}]. " +
"Delegating to subclass implementation for 'onPreHandle' check.",
new Object[]{getName(), path, pathConfig});
}
//The filter is enabled for this specific request, so delegate to subclass implementations
//so they can decide if the request should continue through the chain or not:
// 做一些子类的操作
return onPreHandle(request, response, pathConfig);
}
if (log.isTraceEnabled()) {
log.trace("Filter '{}' is disabled for the current request under path '{}' with config [{}]. " +
"The next element in the FilterChain will be called immediately.",
new Object[]{getName(), path, pathConfig});
}
//This filter is disabled for this specific request,
//return 'true' immediately to indicate that the filter will not process the request
//and let the request/response to continue through the filter chain:
return true;
}