FilterChainProxy是Spring Security Web添加到Servlet容器用于安全控制的一个Filter。从Servlet容器的角度来看,Spring Security Web所提供的安全逻辑就是一个Filter,实现类为FilterChainProxy。实际上FilterChainProxy是一个代理对象,FilterChainProxy内部组合了多个SecurityFilterChain,每个SecurityFilterChain组合了一组Filter,这组Filter虽然也实现了Servlet Filter接口,但它们对于整个Servlet容器来讲是不可见的。对于Servlet容器来讲,Spring Secrutiy Web添加进来的用于安全的过滤器就是FilterChainProxy这一个过滤器,真正对请求的安全处理逻辑,最终由匹配该请求的某个SecurityFilterChain中的多个Filter来完成。
在Spring Security Web框架中,FilterChainProxy由Web安全构建器WebSecurity构建而来。而该构建动作在应用启动过程中Web安全配置阶段执行,具体可以参考Web安全配置类WebSecurityConfiguration。而WebSecurityConfiguration则又由注解@EnableWebSecurity引起。这个触发关系,可以这么理解 :
@EnableWebSecurity => WebSecurityConfiguration => WebSecurity 构建 => FilterChainProxy
缺省情况下FilterChainProxy安全过滤器的名字总是springSecurityFilterChain。
源代码
源代码版本 : Spring Security Web 5.1.4.RELEASE
package org.springframework.security.web;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.firewall.FirewalledRequest;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
public class FilterChainProxy extends GenericFilterBean {
// ~ Static fields/initializers
// ======================================================
private static final Log logger = LogFactory.getLog(FilterChainProxy.class);
// ~ Instance fields
// ======================================================
private final static String FILTER_APPLIED = FilterChainProxy.class.getName().concat(
".APPLIED");
private List<SecurityFilterChain> filterChains;
private FilterChainValidator filterChainValidator = new NullFilterChainValidator();
private HttpFirewall firewall = new StrictHttpFirewall();
// ~ Methods
// =====================================================
public FilterChainProxy() {
}
// 构造函数 :基于一组过滤器链 SecurityFilterChain 构造一个 FilterChainProxy 对象
public FilterChainProxy(SecurityFilterChain chain) {
this(Arrays.asList(chain));
}
// 构造函数 :基于一组过滤器链 SecurityFilterChain 构造一个 FilterChainProxy 对象
public FilterChainProxy(List<SecurityFilterChain> filterChains) {
this.filterChains = filterChains;
}
// InitializingBean 接口定义的当前 bean 的初始化方法
// 使用 filterChainValidator 验证当前对象
@Override
public void afterPropertiesSet() {
filterChainValidator.validate(this);
}
// Filter 接口定义的过滤器主方法 :
// 如果针对该请求尚未应用该过滤器则应用该过滤器
@Override
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 {
// 2019-05-19 : 此分支存在的目的尚未明确
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);
// 当前过滤器其实一个组合了多个过滤器链 SecurityFilterChain 的代理对象,
// 现在找到匹配当前请求的那个 SecurityFilterChain 中的所有安全过滤器
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
chain.doFilter(fwRequest, fwResponse);
return;
}
// 如果针对当前请求有相应的安全过滤器,则将这些安全过滤器组成一个 VirtualFilterChain,
// 虚拟过滤器链,将各个安全过滤器应用到该 请求上,这些安全过滤器应用完之后,在继续
// 应用 chain 上的其他过滤器到该请求
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
}
/**
* Returns the first filter chain matching the supplied URL.
* 返回匹配指定请求的过滤器链中的过滤器,如果没有匹配的过滤器链则返回null
* @param request the request to match
* @return an ordered array of Filters defining the filter chain
*/
private List<Filter> getFilters(HttpServletRequest request) {
for (SecurityFilterChain chain : filterChains) {
if (chain.matches(request)) {
return chain.getFilters();
}
}
return null;
}
/**
* Convenience method, mainly for testing.
*
* @param url the URL
* @return matching filter list
*/
public List<Filter> getFilters(String url) {
return getFilters(firewall.getFirewalledRequest((new FilterInvocation(url, "GET")
.getRequest())));
}
/**
* @return the list of SecurityFilterChains which will be matched against and
* applied to incoming requests.
*/
public List<SecurityFilterChain> getFilterChains() {
return Collections.unmodifiableList(filterChains);
}
/**
* Used (internally) to specify a validation strategy for the filters in each
* configured chain.
*
* @param filterChainValidator the validator instance which will be invoked on during
* initialization to check the FilterChainProxy instance.
*/
public void setFilterChainValidator(FilterChainValidator filterChainValidator) {
this.filterChainValidator = filterChainValidator;
}
/**
* Sets the "firewall" implementation which will be used to validate and wrap (or
* potentially reject) the incoming requests. The default implementation should be
* satisfactory for most requirements.
*
* @param firewall
*/
public void setFirewall(HttpFirewall firewall) {
this.firewall = firewall;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("FilterChainProxy[");
sb.append("Filter Chains: ");
sb.append(filterChains);
sb.append("]");
return sb.toString();
}
// ~ Inner Classes 内部类
// =====================================================
/**
* Internal FilterChain implementation that is used to pass a request through
* the additional internal list of filters which match the request.
* 一个内部类实现,用于将一组内部管理的过滤器应用到指定请求 firewalledRequest 上,应用完
* 这组过滤器之后,继续执行传入的过滤器链 chain
*/
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() + "'");
}
nextFilter.doFilter(request, response, this);
}
}
}
public interface FilterChainValidator {
void validate(FilterChainProxy filterChainProxy);
}
private static class NullFilterChainValidator implements FilterChainValidator {
@Override
public void validate(FilterChainProxy filterChainProxy) {
}
}
}
相关文章
Spring Security Config : WebSecurityConfiguration Web 安全配置
Spring Boot 自动配置 : SecurityAutoConfiguration
Spring Security Web : SecurityFilterChain 安全过滤器概念模型
本文围绕Spring Security展开,介绍了添加到容器用于安全控制的过滤器,它是代理对象,内部组合多个组件,真正的安全处理逻辑由匹配请求的组件完成。还说明了过滤器由安全构建器构建,构建动作在应用启动安全配置阶段执行,同时给出了相关源代码版本和参考文章。
1万+

被折叠的 条评论
为什么被折叠?



