概述:Spring Security 的核心组件

在深入代码之前,我们先理解几个关键角色:

  • DelegatingFilterProxy: 这是 Spring 提供的一个标准 Servlet 过滤器。它的作用是代理(delegate)实际的过滤工作给 Spring IoC 容器中的一个 Bean。这是 Spring Security 能够将自身过滤器链集成到 Servlet 容器(如 Tomcat)的关键。
  • FilterChainProxy: 这是 Spring Security 真正的核心过滤器。它本身就是一个 Filter,并且被注册为 DelegatingFilterProxy 的代理目标。FilterChainProxy 内部维护了一个或多个 SecurityFilterChain,并根据请求 URL 决定使用哪一个链来处理请求。
  • SecurityFilterChain: 这是一个安全过滤器链的抽象。它包含了一系列用于处理特定请求的 Filter(如 UsernamePasswordAuthenticationFilter, BasicAuthenticationFilter, FilterSecurityInterceptor 等)。一个 WebSecurity 配置可以创建多个 SecurityFilterChain,每个链负责不同的 URL 模式。
  • WebSecurity: 这是一个配置构建器。它的主要职责是创建和配置 FilterChainProxy 所需的 SecurityFilterChain 列表。它负责全局的、不针对特定 HTTP 请求的配置,比如设置认证管理器、忽略某些静态资源、配置多个安全规则等。
  • HttpSecurity: 这是 WebSecurity 的内部助手,专门用于构建针对 HTTP 请求的安全规则。我们平时写的 http.authorizeRequests(), http.formLogin()等代码,都是在操作这个 HttpSecurity 对象。每个 HttpSecurity 的配置最终会生成一个 SecurityFilterChain

一句话总结关系@EnableWebSecurity 启动配置 -> WebSecurity (作为总构建器) -> 创建 HttpSecurity (作为具体规则构建器) -> HttpSecurity 构建出 SecurityFilterChain (过滤器链) -> WebSecurity 将所有 SecurityFilterChain 组合并最终创建 FilterChainProxy -> DelegatingFilterProxy 将请求代理给 FilterChainProxy

启动与初始化:@EnableWebSecurity 的魔法

一切始于 @EnableWebSecurity 注解,@EnableWebSecurity 是一个组合注解,它导入了 WebSecurityConfiguration。这个配置类通过 @Import 引入了 Spring Security 的自动配置和核心 Bean 定义。

关键步骤

  1. 创建 WebSecurity Bean: Spring 容器会创建一个名为 springSecurityFilterChainBean,其类型是 FilterChainProxy。这个 Bean 的创建和初始化逻辑都在 WebSecurityConfiguration 中。
  2. 注册 DelegatingFilterProxy: 同时,一个名为 springSecurityFilterChainDelegatingFilterProxy 会被注册到 Servlet 容器中。这个代理过滤器的目标(targetBeanName)就是上面创建的 FilterChainProxy Bean
  3. 设置过滤器顺序: 通过 @Order 注解或 FilterRegistrationBean,确保 DelegatingFilterProxy 在过滤器链中有一个合适的顺序(通常是靠前的位置),以便尽早拦截请求。

核心构建者:WebSecurity 与 HttpSecurity 的分工

当你继承 WebSecurityConfigurerAdapter (在较新版本中是直接定义 SecurityFilterChain Bean) 时,你实际上是在和这两个构建器打交道。
WebSecurity (总设计师)

  • 职责: 负责全局配置。
  • 常用方法:
    • web.ignoring().antMatchers("/css/**", "/js/**"): 完全忽略某些请求,让它们不经过任何 Spring Security 过滤器。这对于静态资源非常有用,可以提升性能。这些请求甚至不会被 DelegatingFilterProxy 拦截。
    • web.authenticationManager(): 设置全局的 AuthenticationManager,用于认证。
    • web.addFilterBefore(...) / addFilterAfter(...): 在所有 SecurityFilterChain 的过滤器之前/之后添加自定义过滤器。
    • web.securityContext().requestCache(): 配置请求缓存策略。

HttpSecurity (具体规则制定者)

  • 职责: 为特定的 URL 模式配置详细的安全规则。每个 configure(HttpSecurity http) 方法(或每个 @Bean SecurityFilterChain)都会创建一个独立的 HttpSecurity 实例。更加详细的请查看spring security中httpSecurity构建DefaultSecurityFilterChain逻辑
  • 常用方法 (链式调用):
    • http.authorizeRequests(): 开始配置授权规则(谁可以访问什么 URL)。
    • http.formLogin(): 配置表单登录。
    • http.csrf(): 配置 CSRF 保护。

关键点:一个 WebSecurity 可以配置多个 HttpSecurity,从而产生多个 SecurityFilterChain。例如:

@Bean
public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
    return http
        .securityMatcher("/api/**") // 这个链只匹配 /api/** 的请求
        .authorizeRequests(authz -> authz.anyRequest().hasRole("API_USER"))
        .httpBasic(withDefaults())
        .build();
}

@Bean
public SecurityFilterChain webAppChain(HttpSecurity http) throws Exception {
    return http
        .authorizeRequests(authz -> authz.anyRequest().authenticated()) // 匹配所有其他请求
        .formLogin(withDefaults())
        .build();
}

关键产物:SecurityFilterChain 与 SecurityFilterProxy 的构建

构建 SecurityFilterChain

  1. 收集所有配置的过滤器: HttpSecurity 内部维护一个 List<Filter>。在你调用 formLogin(), csrf() 等方法时,Spring Security 会把对应的过滤器(如 UsernamePasswordAuthenticationFilter, CsrfFilter)添加到这个列表中。
  2. 排序过滤器: 根据过滤器之间的依赖关系(如 CsrfFilter 必须在 UsernamePasswordAuthenticationFilter 之前),对列表进行排序。
  3. 创建 FilterChain: 将排序后的过滤器列表包装成一个 DefaultSecurityFilterChain 对象。这个对象包含两个关键信息:
  • 一个 RequestMatcher:用于判断当前请求是否应该由这个链处理(例如,/api/**)。
  • 一个 List<Filter>:处理该请求的过滤器列表。

构建 FilterChainProxy
WebSecurity 的最终目标是创建 FilterChainProxy

  1. 收集所有 SecurityFilterChain: WebSecurity 会收集所有通过 HttpSecurity.build() 方法创建的 SecurityFilterChain Bean,并将它们放入一个列表中。
  2. 创建 FilterChainProxy: WebSecurity 使用这个 SecurityFilterChain 列表来实例化 FilterChainProxy
  3. FilterChainProxy 的内部结构:
  • 它持有一个 List<SecurityFilterChain>
  • 它本身实现了 Filter 接口,因此可以被 Servlet 容器调用。
  • 它的 doFilter 方法是整个安全逻辑的入口。

请求处理流程:FilterChainProxy 如何工作

当一个 HTTP 请求到达应用时,流程如下:

  1. Servlet 容器: Tomcat 接收到请求,开始执行过滤器链。
  2. DelegatingFilterProxy: 容器调用 DelegatingFilterProxydoFilter 方法。
  3. 委托: DelegatingFilterProxy 从 Spring 容器中找到名为 springSecurityFilterChainFilterChainProxy Bean,并调用其 doFilter 方法,将 ServletRequest, ServletResponseFilterChain 传递过去。
  4. FilterChainProxy.doFilter(request, response, chain): 这是核心逻辑!
  • 查找匹配的 SecurityFilterChain: FilterChainProxy 遍历它内部维护的 SecurityFilterChain 列表。对每个链,它会调用其 RequestMatchermatches(request) 方法。
  • 第一个匹配者胜出: 一旦找到第一个匹配当前请求 URL 的 SecurityFilterChain,就停止查找。
  • 执行过滤器链: FilterChainProxy 获取到这个匹配的 SecurityFilterChain 后,会依次执行该链中的所有 Filter。
  • 链的末尾: 最后一个过滤器通常是 FilterSecurityInterceptor。它负责最终的授权决策(Access Decision)。它会检查当前用户是否有权限访问请求的资源。如果权限不足,会抛出 AccessDeniedException
  • 异常处理: 如果在过滤器链的任何环节抛出认证或授权异常,FilterChainProxy 会有一个专门的 ExceptionTranslationFilter 来捕获这些异常,并进行处理(例如,重定向到登录页面或返回 403 Forbidden)。
  1. 请求继续: 如果所有过滤器都成功执行,请求最终会到达 FilterChainProxy 构造时传入的原始 FilterChain(即 Servlet 容器的后续过滤器链),并最终到达你的 Controller

总结与图解

请求的核心流程图:

                  +-----------------------------+
                  |      Servlet Container      |
                  | (e.g., Tomcat)              |
                  +-----------------------------+
                             |
                             v
                  +-----------------------------+
                  | DelegatingFilterProxy       |  <-- Registered in web.xml/ServletContext
                  | (targetBeanName: "springSecurityFilterChain") |
                  +-----------------------------+
                             | (delegates to)
                             v
                  +-----------------------------+
                  | FilterChainProxy            |  <-- The real security filter
                  | (Bean: "springSecurityFilterChain") |
                  +-----------------------------+
                             |
                             | 1. Find matching chain for request URL
                             v
                  +-----------------------------+      +-----------------------------+
                  | SecurityFilterChain 1       |      | SecurityFilterChain 2       |
                  | (matcher: "/api/**")        |      | (matcher: "/**")            |
                  | - CsrfFilter                |      | - CsrfFilter                |
                  | - UsernamePasswordFilter    |      | - FormLoginFilter           |
                  | - FilterSecurityInterceptor |      | - FilterSecurityInterceptor |
                  +-----------------------------+      +-----------------------------+
                             ^
                             | 2. Execute filters in the chain
                             |
                  (Authentication & Authorization happens here)

                             | 3. If all OK, continue to app
                             v
                  +-----------------------------+
                  | Your Application (Controller)|
                  +-----------------------------+

FilterChainProxy构建核心流程图:

@EnableWebSecurity
      |
      v
WebSecurityConfiguration (creates beans)
      |
      +---> Creates DelegatingFilterProxy (registers with servlet container)
      |
      +---> Creates WebSecurity (builder)
            |
            +---> User configures web.ignoring() (global ignores)
            |
            +---> User defines one or more SecurityFilterChain Beans (via HttpSecurity)
                  |
                  +---> HttpSecurity 1 -> build() -> SecurityFilterChain 1 (for /api/\*\*)
                  |       - Adds filters (CsrfFilter, etc.)
                  |       - Configures matchers, authorization rules
                  |
                  +---> HttpSecurity 2 -> build() -> SecurityFilterChain 2 (for /\*\*)
                         - Adds filters (CsrfFilter, FormLoginFilter, etc.)
                         - Configures matchers, authorization rules
            |
            +---> WebSecurity collects all SecurityFilterChains
            |
            +---> Creates FilterChainProxy, injecting the list of SecurityFilterChains
                  |
                  +---> DelegatingFilterProxy is configured to delegate to this FilterChainProxy

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐