一、过滤器
Spring Security
的 Servlet
支持基于 Servlet
过滤器,因此首先了解过滤器的作用会很有帮助。
下图为单个 HTTP
请求的处理程序的典型分层。
客户端向应用程序发送一个请求,运行容器创建一个FilterChain
(过滤链),其中包括所有的Filter
实例和Servlet
。过滤器根据URI
路径处理请求 和响应。
在一个SpringMvc
(Spring Boot
)应用程序中,一般只有一个Servlet
实例,也就是 DispatcherServlet
,他们按照指定的顺序(每个Filter
实例实例的顺序非常重要),共同协作。
一个简单的自定义过滤器代码示例:
java
// 使用@ServletComponentScan添加在启动类上扫描该自定义过滤器
@WebFilter(filterName = "simpleFilter", urlPatterns = {"/*"})
@Slf4j
public class SimpleFilter3 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
log.info("初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("业务处理开始");
filterChain.doFilter(servletRequest, servletResponse);
log.info("业务处理结束");
}
public void destroy() {
log.info("销毁");
}
}
二、DelegatingFilterProxy
Spring
提供了一个名为DelegatingFilterProxy
的实现,它允许Servlet
容器和Spring IoC
容器的生命周期之间进行桥接。
Servlet
容器使用自己的标准注册Filter
实例,但它不知道Spring IoC
容器中定义的过滤器Bean
。在有了DelegatingFilterProxy
后就可以很方便的在Servlet
中使用Spring IoC
容器来管理过滤器Bean
。
在请求响应 过程中,DelegatingFilterProxy
从Spring IoC
容器中查询注册的过滤器Bean
对象,然后调用Bean
的过滤方法。
下图为DelegatingFilterProxy
是如何让使用Filter
实例和FilterChain
的。
从DelegatingFilterProxy
源码中可以看到该类包含了Spring IoC
容器和被代理的过滤器:
一个简单的DelegatingFilterProxy使用代码示例:
java
// Spring定义的Bean Filter
@Component("simpleFilter")
@Slf4j
public class SimpleFilter2 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
log.info("初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("业务处理开始");
filterChain.doFilter(servletRequest, servletResponse);
log.info("业务处理结束");
}
public void destroy() {
log.info("销毁");
}
}
@Configuration
public class SimpleConfig {
@Bean
public DelegatingFilterProxyRegistrationBean delegatingFilterProxyRegistrationBean() {
DelegatingFilterProxyRegistrationBean delegatingFilterProxy = new DelegatingFilterProxyRegistrationBean("simpleFilter");
delegatingFilterProxy.addUrlPatterns("/*");
delegatingFilterProxy.setOrder(-5);
Map<String, String> initParameters = new HashMap<>();
initParameters.put("targetFilterLifecycle", "true");
delegatingFilterProxy.setInitParameters(initParameters);
return delegatingFilterProxy;
}
}
三、FilterChainProxy
Spring Security
提供FilterChainProxy
代理类,是Spring Security
使用的核心,用于代理Spring Security
中所有的SecurityFilterChain
,而在SecurityFilterChain
中又包含多个Spring Security
声明的Filter
下图FilterChainProxy
在整个请求响应过程中的作用。
从FilterChainProxy
源码中可以看到该类代理了Spring Security
中所有的SecurityFilterChain
:
FilterChainProxy
本质上是一个特殊的过滤器,通过DelegatingFilterProxy
进行代理,所有其也是一个Bean
对象。
在SecurityFilterChain
过滤链中通常都是Bean
对象,通过FilterChainProxy
进行注册与直接通过Servlet
容器或通过DelegatingFilterProxy
进行注册相比,FilterChainProxy
注册有很多优势:
- 它为
Spring Security
的所有Servlet
支持提供了一个起点 ,如果需要对Spring Security
的Servlet
支持进行故障诊断可以在在FilterchainProxy
中添加一个调试点。 - 可以执行一些不被视为可有可无的任务,例如,清除了
SecurityContext
以避免内存泄漏、应用Spring Security
的HttpFirewall
来保护应用程序免受某些类型的攻击 - 在确定何时应该调用
SecurityFilterChain
方面提供了更大的灵活性,在Servlet
容器中,Filter
实例仅基于URL
被调用。FilterChainProxy
可以通过使用RequestMatcher
接口 ,根据HttpServletRequest
中的任何内容确定调用。