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),可以通过以下方式彻底禁用默认链:
- 排除Spring Boot默认的安全自动配置类
在自动配置类或者启动类上,排除SecurityAutoConfiguration和SpringBootWebSecurityConfiguration(后者是生成默认链的关键类):
// 在启动类中排除 @SpringBootApplication(exclude = {SecurityAutoConfiguration.class, SpringBootWebSecurityConfiguration.class}) // 或者在自动配置类中通过@EnableAutoConfiguration排除 @EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class, SpringBootWebSecurityConfiguration.class})
SpringBootWebSecurityConfiguration是Spring Boot提供的默认安全配置类,它会在没有自定义SecurityFilterChain时生成默认链,直接排除它就能避免默认链的生成。
- 确保自定义配置类被正确加载
当前你的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就不会生成默认链了。
- 验证配置加载顺序
通过添加日志或调试断点查看Bean的加载顺序,确认MySecurityAutoConfiguration确实在SecurityAutoConfiguration之前加载,确保自定义配置先于默认配置生效,避免默认链被提前生成。
总结
只要确保自定义的SecurityFilterChain Bean被Spring正确识别,并且排除掉Spring Boot的默认安全配置类,就能让Spring只使用你定义的过滤器链,不需要依赖@Order注解来调整优先级。
内容的提问来源于stack exchange,提问作者Juan Bustamante

