SpringShiroFilter 的作用
1. 包装 Request 和 Response,使它们由原来的 HttpServlet 系列包装为 ShiroHttpServletRequest
2. 创建 Subject,传递给接下来的过滤器
如果没有定义任何 FilterChainDefinitionMap,那 Shiro 也会把 Request 交给它默认的 SpringShiroFilter 过滤。
3. 更新 SessionLastAccessTime(native sessions)
SpringShiroFilter 的定义
SpringShiroFilter 其实是一个内部类,被定义在 ShiroFilterFactoryBean 中:
private static final class SpringShiroFilter extends AbstractShiroFilter {
protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
super();
if (webSecurityManager == null) {
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
}
setSecurityManager(webSecurityManager);
if (resolver != null) {
setFilterChainResolver(resolver);
}
}
}
从它的构造器看,SpringShiroFilter 只能接受 WebSecurityManager 类型,而 WebSecurityManager 只有一个实现类 DefaultWebSecurityManager。
SpringShiroFilter 的继承关系
其中它继承自 OncePerRequestFilter,也就是每个请求执行一次。在执行的时候会先进入 OncePerRequestFilter.doFilter() 方法,然后进入 AbstractShiroFilter.doFilterInternal() 方法:
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
final FilterChain chain) throws ServletException, IOException {
Throwable t = null;
try {
final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
final ServletResponse response = prepareServletResponse(request, servletResponse, chain);
final Subject subject = createSubject(request, response);
// noinspection unchecked
subject.execute(new Callable() {
public Object call() throws Exception {
updateSessionLastAccessTime(request, response);
executeChain(request, response, chain);
return null;
}
});
} catch (ExecutionException ex) {
t = ex.getCause();
} catch (Throwable throwable) {
t = throwable;
}
if (t != null) {
if (t instanceof ServletException) {
throw (ServletException) t;
}
if (t instanceof IOException) {
throw (IOException) t;
}
// otherwise it's not one of the two exceptions expected by the filter method
// signature - wrap it in one:
String msg = "Filtered request failed.";
throw new ServletException(msg, t);
}
}
上面方法 createSubject(),创建流程见:
之后再调用 execute() 方法,传入了 Callable 接口匿名类,Callable 是 java.util.concurrent 内的接口。个人感觉这里使用 Callable 有些故弄玄虚,其实就是执行了一个方法。
Callable 进行了两个操作:1. 修改了最近一次的访问时间;2. 调用 FilterChain。