架构和核心流程
SpringSecurity的核心流程是一系列过滤器(Filter)组成的过滤器链,在SpringBoot工程中引入SpringSecurity后这些过滤器会自动注册,并在请求中加载用户和权限、检查是否登录、检查是否有权限访问资源等。我们使用SpringSecurity实际上就是配置、扩展或是自定义这些过滤器插入到SpringSecurity的执行流程中,实现我们自己的功能。因此只要我们弄清楚这些过滤器的作用,扩展SpringSecurity实现我们自己的功能就不难了。
HttpSecurity配置
HttpSecurity是SpringSecurity中的一个配置类,用于定义和配置框架的安全规则,包括认证、授权、CSRF、CORS配置等。配置HttpSecurity的方法是创建一个配置类,用于注册SecurityFilterChain这个Bean,它可以通过调用httpSecurity.build()方法创建,在创建它之前我们可以配置HttpSecurity。
package com.gacfox.demo.demosecurity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers("/login").anonymous()
.anyRequest().authenticated();
return httpSecurity.build();
}
}
HttpSecurity是SpringSecurity的核心配置,其中包含的配置项也比较繁杂,实际开发中具体会用到哪些配置项会在后续章节详细介绍。
SecurityContext安全上下文
SecurityContext的概念在Shiro等各类安全框架中都存在。安全上下文顾名思义,就是一个对应当前会话的认证授权信息的封装。其实这很好理解,登录操作就是设置SecurityContext,登出操作就是清空SecurityContext,获取用户信息、权限信息,从SecurityContext中取出相关信息即可。在任何地方,我们都可以使用SecurityContextHolder.getContext()获取对应当前请求的SecurityContext。
过滤器链

SpringSecurity的执行流程其实可以归结为一系列过滤器链。如果全部采用默认配置,按照调用顺序,在一次正常的HTTP请求中,SpringSecurity会使用下列过滤器处理请求:
WebAsyncManagerIntegrationFilter:该过滤器的作用是将SecurityContext和SpringMVC的WebAsyncManager集成,我们需要在SpringMVC中使用异步请求处理功能时,该过滤器能保证我们正确获取SecurityContext,一般无需扩展。
SecurityContextPersistenceFilter:该过滤器用于装载和卸载每次请求中的SecurityContextHolder中的SecurityContext。例如采用Session保存用户信息,该过滤就负责在请求处理前从Session加载SecurityContext,在请求处理后将SecurityContext写回Session。如果有将Session写到Redis的需求,我们只需要使用spring-session-data-redis即可,一般来说不需要扩展该过滤器,除非要将Session写到一些非常规的地方。
HeaderWriterFilter:该过滤器用于在HTTP响应中写入安全相关的响应头,如X-Frame-Options、X-XSS-Protection、X-Content-Type-Options等,通过该过滤器的扩展点可以写入自定义的安全响应头。该过滤器具有默认行为,会默认写入一些安全HTTP响应头,除非有特殊需求一般来说不需要额外对其进行配置。
CsrfFilter:该过滤器在响应中使用CSRF-TOKEN并在请求中验证以防御CSRF攻击,我们可以配置全局使用该过滤器实现CSRF防御,也可以给单独指定的路由添加CSRF校验。在前后端分离中,我们可以单独写一个Controller专门返回CSRF-TOKEN供前端使用。如果希望关闭CSRF防御功能,也可以通过配置全局禁用该过滤器。
LogoutFilter:该过滤器用于处理登出请求,默认会注册在/logout路径下,我们也可以自定义其注册路径,此外还可以通过扩展LogoutSuccessHandler扩展登出成功后的返回信息。实际开发中,我们也可以定义自己的登出接口取代该过滤器。
UsernamePasswordAuthenticationFilter:该过滤器从表单中获取用户名和密码并执行认证,然后根据认证结果返回认证状态。我们可以扩展该过滤器实现更复杂的认证流程,也可以将其禁用,定义我们自己的认证接口取代该过滤器,实际开发中一般采用自定义方式,该过滤器较少使用。
DefaultLoginPageGeneratingFilter:该过滤器用于输出默认登录表单页面,配合UsernamePasswordAuthenticationFilter实现登录功能,在实际开发中一般不会用到。
BasicAuthenticationFilter:该过滤器用于处理HTTP Basic认证,实际开发中真实的项目生产环境极少使用,一般将其直接禁用。
RequestCacheAwareFilter:该过滤器用于保存引发重定向的原始请求,该技术用于非前后端分离项目,在前后端分离项目中没有意义,可以将其禁用。
SecurityContextHolderAwareRequestFilter:用于设置SecurityContext到SecurityContextHolder,一般无需扩展。
AnonymousAuthenticationFilter:该过滤器用于为未登录的用户创建一个匿名(或理解为游客)认证对象,以便在后续的请求中可以识别该用户,一般不需要扩展。
SessionManagementFilter:该过滤器用于会话管理,比如:超时处理、并发登录控制(如限制多设备登录)、单点登录等。我们可以通过配置方式使用该过滤器。
ExceptionTranslationFilter:该过滤器是一个比较关键的过滤器,它用于捕获请求中发生的异常,比如认证异常、鉴权异常等,并根据异常类型执行相应的操作。我们可以扩展该过滤器实现这些异常处理的自定义功能。
FilterSecurityInterceptor:该过滤器是SpringSecurity实现认证鉴权的核心组件,内部包含了认证和检查权限是否存在的逻辑,通常不需要扩展。
实际上SpringSecurity中还有很多其它过滤器在默认配置下没有启用,不过默认情况已经将SpringSecurity的核心执行流程展示清楚了,理解了这些默认过滤器的作用,我们应该已经可以举一反三使用SpringSecurity实现各种功能了。