通过上篇对FilterChainManager的学习,可以知道,FilterChainManager是ShiroFilter的基础,包括维护filter列表、请求路径到过滤器链的映射和代理原过滤器链,从而让shiro的过滤器先执行。
ShiroFilter使用FilterChainManager代理原过滤器链
ShiroFilter是shiro的入口点,当请求路径到达ShiroFilter,shiro根据请求的路径,使用FilterChainManager代理原过滤器链,让请求先经过shiro的过滤器链,再执行原过滤器链。
先来看一下shiroFilter的继承关系。
shiroFilter继承自AbstractShiroFilter,并继承了OncePerRequestFilter,该过滤器用来实现一次请求只经过一个过滤器链。
private static final class SpringShiroFilter extends AbstractShiroFilter {
// 将FilterChainResolver传递进去
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);
}
}
}
FilterChainResolver本质上就是使用FilterChainManager来实现代理原过滤器链,可以看作是FilterChainManager的一层包装。
shiroFilter代码很少,主要继承了AbstractShiroFilter。OncePerRequestFilter过滤器主要实现一次请求只经过一个过滤器链,并调用doFilterInternal方法来具体实现过滤功能:
doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException //该方法由子类实现
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;
}
});
}
...//省略代码,不影响阅读
}
protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain)
throws IOException, ServletException {
// 使用FilterChainResolver来获取代理过滤器链
FilterChain chain = getExecutionChain(request, response, origChain);
// 执行代理过滤器链,由上一篇可知,会先执行shiro的过滤器链,然后执行原过滤器链
chain.doFilter(request, response);
}
AbstractShiroFilter.getExecutionChain
protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
FilterChain chain = origChain;
FilterChainResolver resolver = getFilterChainResolver();
if (resolver == null) {
log.debug("No FilterChainResolver configured. Returning original FilterChain.");
return origChain;
}
// 会调用FilterChainManager来获取代理过滤器链
FilterChain resolved = resolver.getChain(request, response, origChain);
if (resolved != null) {
log.trace("Resolved a configured FilterChain for the current request.");
chain = resolved;
} else {
log.trace("No FilterChain configured for the current request. Using the default.");
}
return chain;
}
由上可知,AbstractShiroFilter会调用FilterChainResolver的getChain()方法。而ShiroFilterFactoryBean(在下一篇讲),在创建ShiroFilter实例的时候,使用的是PathMatchingFilterChainResolver。
PathMatchingFilterChainResolver.getChain()方法如下:
public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
FilterChainManager filterChainManager = getFilterChainManager();
if (!filterChainManager.hasChains()) {
return null;
}
String requestURI = getPathWithinApplication(request);
// 遍历filterChainManager的过滤器链名称,看请求路径是否和过滤器链匹配
for (String pathPattern : filterChainManager.getChainNames()) {
// 如果请求路径和filterChainManager中的过滤器链名称匹配,则获取该名称对应的过滤器链
if (pathMatches(pathPattern, requestURI)) {
if (log.isTraceEnabled()) {
log.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + requestURI + "]. " +
"Utilizing corresponding filter chain...");
}
// 最终调用filterChainManager.proxy来获取代理过滤器链
return filterChainManager.proxy(originalChain, pathPattern);
}
}
return null;
}
由此验证了我们开始说的,shiroFilter最终会使用FilterChainManager来获取代理器链,从而先执行shiro的过滤器链,然后再执行原过滤器链。