最近在學習安全框架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<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();
// 執行默認過濾器如編碼過濾器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);
}
}
下一篇博客將介紹各個過濾器的具體功能