目录
紧接上一篇文章,这一篇我们来看看FilterChainProxy类的运行机制及内部结构。
FilterChainProxy是spring-security框架的核心过滤器,服务启动过程中,系统会根据我们自定义的配置类内容生成FilterChainProxy的对象;服务接收到HTTP请求后,就会将请求转发到该过滤器对象进行处理。
运行机制
前面的篇章里,我们看到FilterChainProxy对象是建造者WebSecurity在构建步骤的最后一步里创建的。
找到WebSecurity的performBuild()方法,如下所示:
WebSecurity
java
@Override
protected Filter performBuild() throws Exception {
List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(
chainSize);
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
postBuildAction.run();
return result;
}
在这里,创建FilterChainProxy对象时,输入了类型为List<SecurityFilterChain>的构造参数securityFilterChains对象,这个参数对象是如何进行赋值的,我们后续探究。我们先来看看SecurityFilterChain这个类。
点击SecurityFilterChain,如下所示:
SecurityFilterChain
public interface SecurityFilterChain {
boolean matches(HttpServletRequest request);
List<Filter> getFilters();
}
在这里,大概可以猜测,SecurityFilterChain的对象会保存待过滤的请求地址及对应的Filter对象。matches()方法用来判断用户请求与配置的请求地址是否匹配,getFilters()方法用来返回对应的过滤器对象。
我们先运行一下程序看看。
假设自定义配置如下:
S ecurityFilterChains
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers("/css/**", "/js/**")
.regexMatchers("/api/public/.*");
}
}
在这里,先进行简单的配置,即设置"/css/**"、 "/js/**"和"/api/public/.*"为不需要过滤的请求地址。
设置断点,如下所示:

这里,可以看到每定义一个请求地址,就会有一个DefaultSecurityFilterChain对象。接下来看看FilterChainProxy对象是如何执行请求过滤的。
点击FilterChainProxy,如下所示:
FilterChainProxy
由于FilterChainProxy实现了Filter类,所以也是一个过滤器,过滤器一般都是执行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);
}
}
点击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) {
fwRequest.reset();
chain.doFilter(fwRequest, fwResponse);
return;
}
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
}
点击getFilters(),如下所示:
private List<Filter> getFilters(HttpServletRequest request) {
for (SecurityFilterChain chain : filterChains) {
if (chain.matches(request)) {
return chain.getFilters();
}
}
return null;
}
在这里,将request与SecurityFilterChain 进行匹配,只要匹配到一个就返回这个SecurityFilterChain下的Filters,后续的SecurityFilterChain 会被忽略。
接下来将Filters交由VirtualFilterChain进行处理,如下所示:
VirtualFilterChain
java
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;
}
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if (currentPosition == size) {
this.firewalledRequest.reset();
originalChain.doFilter(request, response);
} else {
currentPosition++;
Filter nextFilter = additionalFilters.get(currentPosition - 1);
nextFilter.doFilter(request, response, this);
}
}
}
在这里,VirtualFilterChain会调用每个过滤的doFilter()方法进行处理。
内部结构
类图

FilterChainProxy
FilterChainProxy实现了Filter接口,说明FilterChainProxy也是一个过滤器。但是FilterChainProxy不执行过滤任务,而是调用getFilters()方法,筛选出与当前请求匹配的多个过滤器,然后将这些过滤器直接交给VirtualFilterChain进行处理。
FilterChain
这是一个过滤器链接口。
VirtualFilterChain
这是一个过滤器链实现类。该类实例化时会从FilterChainProxy接收多个Filter对象。当外部调用了该VirtualFilterChain对象的doFilter()时,则该VirtualFilterChain对象会确保所有Filter对象的doFilter()方法都被调用。
这里使用了职责链模式来实现这个功能。
小结
FilterChainProxy是一个过滤器代理,自身不执行过滤逻辑,但会筛选出符合条件的过滤器,并将这些过滤器交给VirtualFilterChain过滤器链对象。
VirtualFilterChain过滤器链对象不是过滤器,其通过职责链模式实现了将该链里的所有Filter按顺序执行下去。