SecurityFilterChain
,字面意思"安全过滤器链",是Spring Security Web
对匹配特定HTTP
请求的一组安全过滤器的抽象建模。这样的一个对象在配置阶段用于配置FilterChainProxy
,而FilterChainProxy
在请求到达时会使用所持有的某个SecurityFilterChain
判断该请求是否匹配该SecurityFilterChain
,如果匹配的话,该SecurityFilterChain
会被应用到该请求上。
FilterChainProxy
是Spring Security Web
添加到Servlet
容器用于安全控制的一个Filter
,换句话讲,从Servlet
容器的角度来看,Spring Security Web
所提供的安全逻辑就是一个Filter
,实现类为FilterChainProxy
。而实际上在FilterChainProxy
内部,它组合了多个SecurityFilterChain
,而每个SecurityFilterChain
又组合了一组Filter
,这组Filter
也实现了Servlet Filter
接口,但是它们对于整个Servlet
容器来讲是不可见的。在本文中,你可以简单地将FilterChainProxy
理解成多个SecurityFilterChain
的一个封装。
SecurityFilterChain
接口其实就定义了两个方法 :
- 判断某个请求是否匹配该安全过滤器链 –
boolean matches(HttpServletRequest request)
- 获取该安全过滤器链所对应的安全过滤器 –
List<Filter> getFilters()
这组安全过滤器会最终被应用到所匹配的请求上
从SecurityFilterChain
接口定义看不到一个SecurityFilterChain
对象是如何提供请求匹配的标准的。Spring Security Web
对SecurityFilterChain
提供了缺省的标准实现DefaultSecurityFilterChain
,从DefaultSecurityFilterChain
的实现,你能全面地看到Spring Security Web
在该功能点上的解决方案。
一个DefaultSecurityFilterChain
对象定义时需要提供以下信息 :
- 一个用于匹配特定请求的请求匹配器
requestMatcher
; - 针对所匹配的请求要应用的一组过滤器。
SecurityFilterChain
/DefaultSecurityFilterChain
代码都不算复杂,但是做到了向使用者Servlet
容器屏蔽细节,这也算是软件工程中"关注点分离"这一概念的良好应用。
源代码
源代码版本 : Spring Security Web 5.1.4 RELEASE
1. SecurityFilterChain
接口定义
package org.springframework.security.web;
import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
public interface SecurityFilterChain {
boolean matches(HttpServletRequest request);
List<Filter> getFilters();
}
2. SecurityFilterChain
标准实现DefaultSecurityFilterChain
package org.springframework.security.web;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
public final class DefaultSecurityFilterChain implements SecurityFilterChain {
private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class);
private final RequestMatcher requestMatcher;
private final List<Filter> filters;
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
this(requestMatcher, Arrays.asList(filters));
}
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
logger.info("Creating filter chain: " + requestMatcher + ", " + filters);
this.requestMatcher = requestMatcher;
this.filters = new ArrayList<>(filters);
}
public RequestMatcher getRequestMatcher() {
return requestMatcher;
}
public List<Filter> getFilters() {
return filters;
}
public boolean matches(HttpServletRequest request) {
return requestMatcher.matches(request);
}
@Override
public String toString() {
return "[ " + requestMatcher + ", " + filters + "]";
}
}