最近在学习安全框架spring Security,想弄清楚其中实现的具体步骤,于是下定决心,研究一下Spring Security源码,这篇博客的目的是想把学习过程记录下来。学习过程中主要参考了http://dead-knight.iteye.com/blog/1511389大神的博客,然后在其基础上,进行更详细的说明
在类org.springframework.web.filter.DelegatingFilterProxy的doFilter方法中可以看到,过滤器执行流程实际上是让委托执行实际的doFilter操作
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
Filter delegateToUse = this.delegate;
if (delegateToUse == null) {
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
}
// 初始化springSecurityFilterChain,详解请移步2.3
this.delegate = initDelegate(wac);
}
delegateToUse = this.delegate;
}
}
// 让委托执行实际的doFilter操作
invokeDelegate(delegateToUse, request, response, filterChain);
}
通过前面几篇博客的分析,我们也知道这里的delegateToUse实际上是org.springframework.security.web.FilterChainProxy
接下来看FilterChainProxy中的doFilter执行流程
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if (clearContext) {
try {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
doFilterInternal(request, response, chain);
} finally {
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
} else {
doFilterInternal(request, response, chain);
}
}
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 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();
// 执行默认过滤器如编码过滤器EncodingFilter,转换请求方式过滤器HiddenHttpMethodFilter等
chain.doFilter(fwRequest, fwResponse);
return;
}
// 把实际doFilter任务交给VirtualFilterChain处理
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
}
// VirtualFilterChain的doFilter方法
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();
// 执行Filter的doFilter操作
originalChain.doFilter(request, response);
} else {
// 当前位置加一
currentPosition++;
// 根据当前位置从过滤器列表中取出一个Filter
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() + "'");
}
// 执行Filte r的doFilter操作
// 把自身作为参数传递给doFilter方法,这样doFilter方法最后会调用VirtualFilterChain的doFilter方法,这样控制就又回到了VirtualFilterChain
nextFilter.doFilter(request, response, this);
}
}
下一篇博客将介绍各个过滤器的具体功能