章节索引 :

Spring Security 安全过滤器

1. 前言

上一节中我们了解到了 Spring Security 安全框架是由一系列有序的安全过滤器组成的,本节将重点讨论 Spring Security 内置安全过滤器的顺序及含义。

Spring 将自己体系内的过滤器交由「过滤器代理 FilterChainProxy」管理,Spring Security 在「过滤器代理 FilterChainProxy」中加入了「安全过滤器链 SecurityFilterChain」实现安全保护功能。

在 Spring Security 各个模块中,内置已实现了一系列的「安全过滤器」,可以满足常见的认证、鉴权等功能需求。

在 Spring Security 5.3.2 中,共内置了 33 个安全过滤器。

本节主要讨论 Spring Security 内置的安全过滤器。

2. 内置安全过滤器

2.1 内置安全过滤器的声明

Spring Security 中的 SecurityFilterChain 对象,是通过 HttpSecurity 类来使用,它还提供了安全过滤器增、减的调用接口。

如前文所述,安全过滤器的执行顺序是至关重要的,而顺序的确定是由 FilterComparator 对象实现的。

FilterComparator 类的全路径为 org.springframework.security.config.annotation.web.builders.FilterComparator

在其构造的时候配置了过滤器的基本顺序,代码如下:

FilterComparator() {
  FilterComparator.Step order = new FilterComparator.Step(100, 100);
  this.put(ChannelProcessingFilter.class, order.next());
  this.put(ConcurrentSessionFilter.class, order.next());
  this.put(WebAsyncManagerIntegrationFilter.class, order.next());
  this.put(SecurityContextPersistenceFilter.class, order.next());
  this.put(HeaderWriterFilter.class, order.next());
...
  this.put(SessionManagementFilter.class, order.next());
  this.put(ExceptionTranslationFilter.class, order.next());
  this.put(FilterSecurityInterceptor.class, order.next());
  this.put(SwitchUserFilter.class, order.next());
}

注意,以上 FilterComparator 中的定义仅作为内置过滤器排序的依据,并不等于过滤器的真正注入。

除了内置的过滤器外,当我们需要添加自定义过滤器的时候,也需要依赖 FilterComparator 对象完成顺序的配置。实际开发时可用以下方法完成向指定顺位插入过滤器的功能:http.addFilterAfterhttp.addFilterBeforehttp.addFilterhttp.addFilterAthttpHttpSecurity 实例)。

另一方面,HttpSecurity 还为各个内置过滤器提供了配置接口。例如:针对 HeaderWriterFilter 提供了 headers() 方法,用于获取或为 HeaderWriterFilter 配置参数,例如设置响应缓存时效 Expires 等 。HttpSecurity 在构建时,会根据已有的配置信息逐一对 Filter 进行实例化。HttpSecurity 还完成了对请求地址的配置,通过 RequestMatcherConfigurer 对象使请求地址与 Filter 匹配。

2.2 内置过滤器总览

图片描述

内容过滤器总览
Spring Security 内置了 33 种安全过滤器,其顺序、名称及作用如下表所示:
顺序号 过滤器名称 简述
1 ChannelProcessingFilter 检查 web 请求通道,如:http、https
2 ConcurrentSessionFilter 检查 Session 状态,更新 Session 最后访问时间
3 WebAsyncManagerIntegrationFilter 关联 Spring Web 上下文和 Spring Security 上下文
4 SecurityContextPersistenceFilter 从 Session 构建 SecurityContext
5 HeaderWriterFilter 往请求头或响应头里写入信息
6 CorsFilter 跨域请求头
7 CsrfFilter 跨站请求伪造
8 LogoutFilter 注销过滤器
9 OAuth2AuthorizationRequestRedirectFilter OAuth2 请求重定向
10 Saml2WebSsoAuthenticationRequestFilter SAML2 单点登录认证请求过滤器
11 X509AuthenticationFilter X509 认证过滤器
12 AbstractPreAuthenticatedProcessingFilter 预认证处理
13 CasAuthenticationFilter 单点认证过滤器
14 OAuth2LoginAuthenticationFilter OAuth2 认证过滤器
15 Saml2WebSsoAuthenticationFilter SAML2 单点登录认证过滤器
16 UsernamePasswordAuthenticationFilter 用户名密码认证过滤器
17 ConcurrentSessionFilter 检查 Session 状态,更新 Session 最后访问时间。第二次出现。
18 OpenIDAuthenticationFilter Open ID 认证过滤器
19 DefaultLoginPageGeneratingFilter 生成 /login 页面
20 DefaultLogoutPageGeneratingFilter 生成 /logout 页面
21 DigestAuthenticationFilter 数字签名认证过滤器
22 BearerTokenAuthenticationFilter Bearer Token 认证过滤器
23 BasicAuthenticationFilter 基本身份认证过滤器
24 RequestCacheAwareFilter 缓存请求状态过滤器
25 SecurityContextHolderAwareRequestFilter 安全上下文请求辅助过滤器
26 JaasApiIntegrationFilter JAAS 认证授权过滤器
27 RememberMeAuthenticationFilter 实现记住我功能
28 AnonymousAuthenticationFilter 匿名认证过滤器
29 OAuth2AuthorizationCodeGrantFilter OAuth2 认证授权码
30 SessionManagementFilter 管理 Session
31 ExceptionTranslationFilter 异常事件处理过滤器
32 FilterSecurityInterceptor 动态权限配置
33 SwitchUserFilter 切换账户

2.3 常用内置过滤器的具体说明

内置过滤器的参数设置通过 HttpSecurity 相应的配置方法完成。

2.3.1 ChannelProcessingFilter

ChannelProcessingFilter 的用于检测请求的通道,例如 HttpHttps 等,可以实现访问请求在不同通道间的跳转。

ChannelProcessingFilter 的配置通过 HttpSecurity.requiresChannel() 方法获取。

例如:强制使用 Https 通道访问。

http.requiresChannel().antMatchers("/users").requiresSecure();

2.3.2 ConcurrentSessionFilter

此过滤器在默认情况下出现两次,其工作内容大致分两步:

  1. 判断 Session 是否存在,如果存在则获取,否则结束;
  2. 判断 Session 是否过期,如果过期则执行退出操作,否则更新 Session 时间。

ConcurrentSessionFilter 的配置通过 HttpSecurity.sessionManagement() 方法获取。

例如:设置 Session 无效时的跳转 URL。

http.sessionManagement().invalidSessionUrl("/login");

2.3.3 WebAsyncManagerIntegrationFilter

WebAsyncManagerIntegrationFilter 用于关联 SecurityContext 上下文。

此过滤器无配置公布的方法。

2.3.4 SecurityContextPersistenceFilter

SecurityContextPersistenceFilter 用于从 Session 构建 SecurityContext。具体分为两步:

  1. 请求开始时,将 SecurityContextRepository 中的 SecurityContext 对象存入 SecurityContextHolder;
  2. 请求完成时,清理 SecurityContextHolder 中的 SecurityContext 对象,并产生新的 SecurityContext 对象放入到 SecurityContextRepository 中,以保证并发环境下的数据一致性。

SecurityContextPersistenceFilter 的配置通过 HttpSecurity.securityContext() 方法获取。

2.3.5 HeaderWriterFilter

HeaderWriterFilter 用于往请求头或响应头里写入信息。

HeaderWriterFilter 的配置通过 HttpSecurity.headers() 方法获取。默认支持的 Header 包括:

Header [name: X-Content-Type-Options, values: [nosniff]]
Header [name: X-XSS-Protection, values: [1; mode=block]]
Header [name: Cache-Control, values: [no-cache, no-store, max-age=0, must-revalidate]]
Header [name: Pragma, values: [no-cache]]
Header [name: Expires, values: [0]]

2.3.6 CorsFilter

CorsFilter 用于配置跨域请求策略。当一个请求中,来源与目标的协议、主机名、端口三者任一不同,即为跨域,在实际开发中如果遇到类似 header is present on the requested resource. 的错误时,往往是因为跨域配置不正确导致。

CorsFilter 的配置通过 HttpSecurity.cors() 方法获取。例如,禁用跨域验证:

http.cors().disable();

2.3.7 CsrfFilter

CsrfFilter 用于验证消息来源,防范跨站请求伪造,此项功能需要前端的配合。

CsrfFilter 的配置通过 HttpSecurity.csrf() 方法获取。例如,禁用 Csrf:

http.csrf().disable();

2.3.8 LogoutFilter

LogoutFilter 用于注销登录状态。

LogoutFilter 的配置通过 HttpSecurity.logout() 方法获取。例如,设置退出后的跳转页面。

http.logout().logoutSuccessUrl("/login");

2.3.9 UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter 用于处理用户名、密码认证。

UsernamePasswordAuthenticationFilter 的配置通过 HttpSecurity.formLogin() 方法获取。例如,设置用户名参数为「mobile」:

http.formLogin().usernameParameter("mobile")

UsernamePasswordAuthenticationFilter Spring Security 认证中较为常用的过滤器,我们会在后续章节重点展开。

2.3.10 ExceptionTranslationFilter

ExceptionTranslationFilter 用于异常事件处理。异常事件有前述过滤器抛出,异常共分为 2 类,一类是认证异常,另一类是权限异常。

ExceptionTranslationFilter 的配置通过 HttpSecurity.exceptionHandling() 方法获取。

ExceptionTranslationFilter 同样较为常用,将在后续章节中重点展开。

3 增加自定义的 Filter

在 HttpSecurity 对象中增加自定义 Filter 可用于实现认证方式的扩展等场景,扩展 Filter 有两步很重要,第一是实现 javax.servlet.Filter 接口;第二是指定新过滤器的位置。

例如,扩展自定义接口 SimpleFilter。

  1. 自定义接口类
public class SimpleFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("In SimpleFilter");
    }
}
  1. 加入到指定位置,比如加在 UsernamePasswordAuthenticationFilter 之前
http.addFilterBefore(new SimpleFilter(), UsernamePasswordAuthenticationFilter.class);

4. 小结

本节我们介绍了 Spring Security 过滤器的作用及其顺序,主要的知识点有:

  • Spring Security 通过扩展 Spring 过滤器实现安全相关业务逻辑;
  • Spring Security 目前原生实现了 33 个过滤器,每个过滤器有固定的顺序及应用场景;
  • Spring Security 可以的插入自定义的过滤器,并且指定过滤器的位置。

Spring Security 过滤器几乎是所有安全功能的核心,在后续章节中还会围绕过滤器展开讨论。下节我们将介绍 Spring Security 的异常回收机制。