spring security 是如何将自己的过滤器加到了tomcat的过滤器链中的?
原理也就是这样:
1.当过滤器链执行到DelegatingFilterProxy的doFilter方法时,DelegatingFilterProxy委托给了FilterChainProxy去处理。(这里是用来委托模式)
2.FilterChainProxy将自己的过滤器链拿过来然后执行doFilter方法。
FilterChainProxy的doFilterInternal方法源码:
private void doFilterInternal(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FirewalledRequest fwRequest = firewall
.getFirewalledRequest((HttpServletRequest) request);
HttpServletResponse fwResponse = firewall
.getFirewalledResponse((HttpServletResponse) response);
//获取到自己过滤器链
List<Filter> filters = getFilters(fwRequest);
//如果没有自己的过滤器链,则回到原来的过滤器链
if (filters == null || filters.size() == 0) {
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(fwRequest)
+ (filters == null ? " has no matching filters"
: " has an empty filter list"));
}
fwRequest.reset();
chain.doFilter(fwRequest, fwResponse);
return;
}
//调用自己的过滤器链
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
}
接着看一下VirtualFilterChain静态内部类,这里面实现了FilterChain接口。
FilterChain接口用于通知 Web 容器把请求交给 Filter 链中的下一个 Filter 去处理,如果当前调用此方法的 Filter 对象是Filter 链中的最后一个 Filter,那么将把请求交给目标 Servlet 程序去处理。
而该类重写了逻辑,是最后一个Filter后交给原过滤器链
private static class VirtualFilterChain implements FilterChain {
private final FilterChain originalChain;
private final List<Filter> additionalFilters;
private final FirewalledRequest firewalledRequest;
private final int size;
private int currentPosition = 0;
private VirtualFilterChain(FirewalledRequest firewalledRequest,
FilterChain chain, List<Filter> additionalFilters) {
this.originalChain = chain;
this.additionalFilters = additionalFilters;
this.size = additionalFilters.size();
this.firewalledRequest = firewalledRequest;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
//如果没有下一个过滤器,则回到原过滤器链
if (currentPosition == size) {
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " reached end of additional filter chain; proceeding with original chain");
}
// Deactivate path stripping as we exit the security filter chain
this.firewalledRequest.reset();
originalChain.doFilter(request, response);
}
else {
currentPosition++;
//获取当前过滤器
Filter nextFilter = additionalFilters.get(currentPosition - 1);
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " at position " + currentPosition + " of " + size
+ " in additional filter chain; firing Filter: '"
+ nextFilter.getClass().getSimpleName() + "'");
}
//执行这个过滤器,
//而每个过滤器内最后都有一个这样的方法chain.doFilter(request,response); 去执行this这个类的doFilter方法,也就是又回来了,进行了循环
nextFilter.doFilter(request, response, this);
}
}
}
总结:其实就是又套了一层,将DelegatingFilterProxy过滤器当成servlet,然后执行了一次FilterChainProxy这个过滤器链。