Skip to content

FilterChainProxy 和 SecurityFilterChain 是什么?一个应用能有多条安全过滤器链吗? ​

  • 标签:Spring Security、认证授权、后端

🏛 业务架构师 ​

FilterChainProxy 是 Spring Security 的总入口(一个 Servlet Filter,由 DelegatingFilterProxy 桥接到 Spring 容器);SecurityFilterChain 是它内部按序组织的一串安全过滤器。一个应用可以配置多条 SecurityFilterChain——按匹配规则(路径、Host、Header)选择生效的链。

多链配置示例:

java
@Bean
@Order(1)
SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
    http.securityMatcher("/api/**")
        .authorizeHttpRequests(a -> a.anyRequest().authenticated())
        .sessionManagement(s -> s.sessionCreationPolicy(STATELESS))
        .httpBasic(Customizer.withDefaults());
    return http.build();
}

@Bean
@Order(2)
SecurityFilterChain webChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(a -> a.requestMatchers("/admin/**")
            .hasRole("ADMIN").anyRequest().permitAll())
        .formLogin(Customizer.withDefaults());
    return http.build();
}

业务价值(多链的真实场景):一套应用同时服务 API(无状态 Token)与后台页面(有状态 Session)——两套完全不同的认证策略、CSRF 策略(API 链关 CSRF、页面链开着)、登录方式,用多链各管各的;再如开放平台 /open/** 走签名验证、内部接口走 SSO——按业务分区隔离安全策略,而不是一条链里堆 if-else。

架构提醒:多链按 Order 匹配(先命中先用),链的划分要对齐业务边界(对外 API / 管理后台 / 健康检查),并且每条链都要显式收尾(anyRequest 定义好),别留"漏配默认放行"的缝——安全配置的模糊地带就是攻击面。

🏗 系统架构师 ​

FilterChainProxy = Spring Security 的总入口(一个 servlet Filter,注册名 springSecurityFilterChain):接收所有请求后,按 RequestMatcher 选择匹配的 SecurityFilterChain 执行——本质是安全策略的路由器。

SecurityFilterChain = 一条具体的过滤器序列:包含该场景的过滤器组合(认证方式、CSRF 策略、授权规则各自的 filter)。请求匹配到哪条链就走哪套规则——策略按域隔离。

一个应用能有多条链吗?能,而且是生产标配:

java
@Bean
SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
    http.securityMatcher("/api/**")
        .csrf(csrf -> csrf.disable())
        .sessionManagement(s -> s.sessionCreationPolicy(STATELESS))
        .authorizeHttpRequests(a -> a.anyRequest().authenticated())
        .oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()));
    return http.build();
}

@Bean
SecurityFilterChain webChain(HttpSecurity http) throws Exception {
    http.securityMatcher("/**")
        .formLogin(Customizer.withDefaults())      // 传统表单会话
        .authorizeHttpRequests(a -> a
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated());
    return http.build();
}

架构价值(多链分治):

  • API 与 Web 双形态共存:/api/** 无状态 JWT(关 CSRF/Session),管理后台表单会话(开 CSRF)——两种安全模型互不污染;
  • 多租户/多渠道隔离:不同域名(securityMatcher 支持主机匹配)不同认证体系(主站 OAuth2 登录、开放平台 API Key);
  • 匹配顺序即优先级:FilterChainProxy 按声明序首个匹配生效——更具体的 matcher 放前面的链(顺序配置错误是高频 bug,宽 matcher 抢先会把请求吞进错误的链)。

一句话:FilterChainProxy 是"安全域网关",SecurityFilterChain 是域内的规则包——理解这对组合就理解了 Spring Security 的拓扑。

💻 全栈开发专家 ​

FilterChainProxy:Spring Security 的总入口(一个 DelegatingFilterProxy 桥接到 Servlet 容器),职责单一——根据请求选一条 SecurityFilterChain 并放行执行,本身不做安全逻辑。

SecurityFilterChain:一组安全过滤器的有序组合 + 一条匹配规则(RequestMatcher)。FilterChainProxy 持有有序列表,首个匹配的链被选中(只走一条,不是全部都走),不匹配则放行到容器原生过滤器链。

一个应用可以有多条链吗?可以,这是标准做法:

java
@Bean
@Order(1)
SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
    http.securityMatcher("/api/**")            // 匹配规则
        .authorizeHttpRequests(a -> a.anyRequest().authenticated())
        .oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()))
        .sessionManagement(s -> s.sessionCreationPolicy(STATELESS));
    return http.build();
}

@Bean
@Order(2)
SecurityFilterChain webChain(HttpSecurity http) throws Exception {
    http.securityMatcher("/**")                // 兜底
        .authorizeHttpRequests(a -> a.requestMatchers("/login").permitAll()
                                .anyRequest().authenticated())
        .formLogin(Customizer.withDefaults());
    return http.build();
}

工程应用场景(我用过的三种):

  1. API 与页面分离:/api/** 走 JWT 无状态链,管理页面走 session+表单登录;
  2. 多租户/多域名:不同子域不同认证方式(OAuth2 vs SAML);
  3. 新旧过渡:老接口 basic auth、新接口 JWT 双链并行迁移。

踩坑提醒:@Order 决定匹配优先级,order 错了「兜底链挡在前面」所有请求都走错链(典型症状:/api 请求被重定向到登录页);链内 securityMatcher 与链外 requestMatchers 职责别混;调试用 logging.level.org.springframework.security=TRACE 看链选择过程。