public void afterPropertiesSet() {
filterChainValidator.validate(this);
}
启动的时候会校验过滤器链。当然默认实现是空的,即不会校验什么。但是框架也提供了一个default的实现类,可以通过set方法注入。
public class DefaultFilterChainValidator implements FilterChainProxy.FilterChainValidator {
public void validate(FilterChainProxy fcp) {
for (SecurityFilterChain filterChain : fcp.getFilterChains()) {
checkLoginPageIsntProtected(fcp, filterChain.getFilters());
checkFilterStack(filterChain.getFilters());
}
checkPathOrder(new ArrayList<SecurityFilterChain>(fcp.getFilterChains()));
checkForDuplicateMatchers(new ArrayList<SecurityFilterChain>(
fcp.getFilterChains()));
}
这个类的入口:
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();
chain.doFilter(fwRequest, fwResponse);
return;
}
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
}
这里,
1.首先会对请求进行防火墙包装处理,将一些不符合要求的url包装成符合要求的,具体可以看HttpFireWall这篇文章。防止这些请求绕过安全检查。
2.List filters = getFilters(fwRequest);
这里会将filterchains中的所有chains与我们的请求路径做匹配,注意只有一个filterchain将会被匹配。所以我们在定义filterchain的路径时,需要注意他们的路径以及我们需要的安全检查顺序。这里返回的是该匹配到chain的所有filters。
3.最后创建一个虚拟的chain执行。
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);