如何仅当依赖模块未定义SecurityFilterChain时加载通用模块的该过滤器链?
解决方法
方法一:禁用Spring Security默认自动配置,配合@ConditionalOnMissingBean
在通用模块的安全配置类上添加@EnableWebSecurity(该注解会自动禁用Spring Boot的默认安全自动配置),然后在通用的SecurityFilterChain Bean方法上保留@ConditionalOnMissingBean(SecurityFilterChain.class):
@Configuration @EnableWebSecurity public class CommonSecurityConfiguration { @Bean @ConditionalOnMissingBean(SecurityFilterChain.class) public SecurityFilterChain commonSecurityFilterChain(HttpSecurity http) throws Exception { // 编写你的通用安全过滤链配置 http.authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .formLogin(form -> form .permitAll() ); return http.build(); } }
原理
@EnableWebSecurity会关闭Spring Boot自动配置的默认SecurityFilterChain,此时Spring上下文中只有当依赖模块自定义了SecurityFilterChain Bean时,该类型的Bean才存在。如果没有自定义Bean,@ConditionalOnMissingBean条件触发,通用模块的过滤链会被创建并生效。
方法二:自定义Condition判断是否存在非默认的SecurityFilterChain
如果不想禁用默认自动配置,可以自定义一个Condition,仅当不存在自定义的SecurityFilterChain时才加载通用过滤链:
- 实现Condition接口:
public class NoCustomSecurityFilterChainCondition implements Condition { private static final String SPRING_SECURITY_AUTO_CONFIG_PACKAGE = "org.springframework.boot.autoconfigure.security.servlet"; @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { BeanFactory beanFactory = context.getBeanFactory(); String[] securityFilterChainBeanNames = beanFactory.getBeanNamesForType(SecurityFilterChain.class); for (String beanName : securityFilterChainBeanNames) { BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName); String beanClassName = beanDef.getBeanClassName(); // 判断bean是否来自Spring Security自动配置包,不是则视为自定义 if (beanClassName != null && !beanClassName.startsWith(SPRING_SECURITY_AUTO_CONFIG_PACKAGE)) { return false; } } // 仅存在默认自动配置的过滤链,加载通用过滤链 return true; } }
- 在通用模块的
SecurityFilterChainBean上使用该Condition:
@Configuration public class CommonSecurityConfiguration { @Bean @Conditional(NoCustomSecurityFilterChainCondition.class) public SecurityFilterChain commonSecurityFilterChain(HttpSecurity http) throws Exception { // 通用安全配置逻辑 return http.build(); } }
原理
自定义Condition会扫描所有SecurityFilterChain类型的Bean,排除Spring Security自动配置生成的默认Bean,只要存在其他来源的自定义Bean,就不加载通用过滤链;反之则加载。
方法三:使用@ConditionalOnProperty配合开关(可选)
如果需要更灵活的控制,可以给通用过滤链添加开关属性,同时结合@ConditionalOnMissingBean:
- 在通用模块的配置类中:
@Configuration public class CommonSecurityConfiguration { @Bean @ConditionalOnMissingBean(SecurityFilterChain.class) @ConditionalOnProperty(name = "security.common.enabled", havingValue = "true", matchIfMissing = true) public SecurityFilterChain commonSecurityFilterChain(HttpSecurity http) throws Exception { // 通用配置 return http.build(); } }
- 依赖模块如果不需要通用过滤链,除了自定义
SecurityFilterChain,还可以在配置文件中关闭:
security.common.enabled=false
原理
通过配置属性开关,默认开启通用过滤链,当依赖模块自定义了过滤链或主动关闭开关时,通用过滤链不会加载。
内容的提问来源于stack exchange,提问作者Ankit Ghildiyal
相关产品推荐
相关产品推荐

