You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot应用为何存在两条Security Filter Chain?

问题描述

我在Spring Boot应用中定义了如下过滤器链Bean:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, MyTokenIntrospector myTokenIntrospector) throws Exception {
    return http
            .httpBasic(AbstractHttpConfigurer::disable)
            .formLogin(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(
                    authorizeHttpRequests -> authorizeHttpRequests
                            .requestMatchers("/actuator/health").permitAll()
                            .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
                            .requestMatchers(HttpMethod.OPTIONS).permitAll() //for csrf OPTIONS queries
                            .anyRequest().authenticated()
            )
            .csrf(AbstractHttpConfigurer::disable)
            .addFilterAfter(new MyAuthExtractorFilter(), BearerTokenAuthenticationFilter.class)
            .oauth2ResourceServer(oauth2 -> oauth2
                    .bearerTokenResolver(new MyBasicTokenResolver())
                    .opaqueToken(opaqueToken -> opaqueToken.introspector(myTokenIntrospector))
                    .authenticationEntryPoint(new BasicAuthenticationEntryPoint())
            )
            .sessionManagement(sessionManager -> sessionManager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .build();
}

但发现Spring Boot并没有使用我定义的这条链,而是调用了另一条默认链。我可以给这个Bean加@Order(1)注解让它生效,但想搞清楚为什么会存在两条过滤器链。

在org.springframework.security.WebSecurityConfiguration的这段代码里打断点时,发现this.securityFilterChains里有2条链:一条是我自定义的,另一条是默认生成的。

public Filter springSecurityFilterChain() throws Exception {
    boolean hasFilterChain = !this.securityFilterChains.isEmpty();
    if (!hasFilterChain) {
        this.webSecurity.addSecurityFilterChainBuilder(() -> {
            this.httpSecurity.authorizeHttpRequests((authorize) -> {
                ((AuthorizeHttpRequestsConfigurer.AuthorizedUrl)authorize.anyRequest()).authenticated();
            });
            this.httpSecurity.formLogin(Customizer.withDefaults());
            this.httpSecurity.httpBasic(Customizer.withDefaults());
            return (SecurityFilterChain)this.httpSecurity.build();
        });
    }

请问能不能让Spring只使用我定义的过滤器链?还是必须加@Order(1)才能让自定义链生效?

更新说明

我正在为所有Spring应用构建一个Spring Boot安全库,完整的安全配置类如下:

@Configuration
@ComponentScan(basePackages = {"org.app.security"}, excludeFilters = {@ComponentScan.Filter(Configuration.class)})
@EnableWebSecurity
public class MySecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, MtServerTokenIntrospector mtserverTokenIntrospector) throws Exception {
        return http
                .httpBasic(AbstractHttpConfigurer::disable)
                .formLogin(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(
                        authorizeHttpRequests -> authorizeHttpRequests
                                .requestMatchers("/actuator/health").permitAll()
                                .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
                                .requestMatchers(HttpMethod.OPTIONS).permitAll() //for csrf OPTIONS queries
                                .anyRequest().authenticated()
                )
                .csrf(AbstractHttpConfigurer::disable)
                .addFilterAfter(new MyAuthExtractorFilter(), BearerTokenAuthenticationFilter.class)
                .oauth2ResourceServer(oauth2 -> oauth2
                        .bearerTokenResolver(new MyBasicTokenResolver())
                        .opaqueToken(opaqueToken -> opaqueToken.introspector(mtserverTokenIntrospector))
                        .authenticationEntryPoint(new BasicAuthenticationEntryPoint())
                )
                .sessionManagement(sessionManager -> sessionManager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .build();
    }
}

同时配置了自动配置类:

@Configuration
@AutoConfigureBefore(SecurityAutoConfiguration.class)
@AutoConfigureAfter(MyHttpClientAutoConfiguration.class)
@ConditionalOnProperty(prefix = "app.security", name = "enabled", havingValue = "true", matchIfMissing = true)
@ComponentScan(basePackages = "org.app.security.config")
public class MySecurityAutoConfiguration {
}
解决方案

为什么会出现两条过滤器链?

Spring Security的WebSecurityConfiguration会在检测到没有自定义SecurityFilterChain Bean时生成默认链,但你这里已经定义了自定义链却还是出现默认链,大概率是因为自动配置类的加载顺序或组件扫描范围问题:

  • 你的MySecurityAutoConfiguration用了@AutoConfigureBefore(SecurityAutoConfiguration.class),但如果SecurityAutoConfiguration已经提前加载,或者你的自定义配置类没有被正确扫描到,Spring可能还是会触发默认链的生成逻辑。
  • 另一种可能是组件扫描范围重复或遗漏,导致Spring同时加载了自定义配置和默认的安全自动配置。

如何让Spring只使用自定义过滤器链?

不需要强制加@Order(1),可以通过以下方式彻底禁用默认链:

  1. 排除Spring Boot默认的安全自动配置类
    在自动配置类或者启动类上,排除SecurityAutoConfiguration和SpringBootWebSecurityConfiguration(后者是生成默认链的关键类):
// 在启动类中排除
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, SpringBootWebSecurityConfiguration.class})

// 或者在自动配置类中通过@EnableAutoConfiguration排除
@EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class, SpringBootWebSecurityConfiguration.class})

SpringBootWebSecurityConfiguration是Spring Boot提供的默认安全配置类,它会在没有自定义SecurityFilterChain时生成默认链,直接排除它就能避免默认链的生成。

  1. 确保自定义配置类被正确加载
    当前你的MySecurityAutoConfiguration扫描的是org.app.security.config,而MySecurityConfiguration在org.app.security下,可能没被扫描到。修改自动配置类的扫描范围:
@ComponentScan(basePackages = {"org.app.security", "org.app.security.config"})

或者直接在MySecurityAutoConfiguration中导入MySecurityConfiguration:

@Import(MySecurityConfiguration.class)

这样能确保自定义的SecurityFilterChain Bean被Spring容器识别,WebSecurityConfiguration就不会生成默认链了。

  1. 验证配置加载顺序
    通过添加日志或调试断点查看Bean的加载顺序,确认MySecurityAutoConfiguration确实在SecurityAutoConfiguration之前加载,确保自定义配置先于默认配置生效,避免默认链被提前生成。

总结

只要确保自定义的SecurityFilterChain Bean被Spring正确识别,并且排除掉Spring Boot的默认安全配置类,就能让Spring只使用你定义的过滤器链,不需要依赖@Order注解来调整优先级。

内容的提问来源于stack exchange,提问作者Juan Bustamante

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:53:18