如何排除Spring Boot Security内部私有配置类OAuth2SecurityFilterChainConfiguration
如何排除Spring Boot OAuth2资源服务器的自动配置内部类
问题背景
我有一个实现基础认证和OAuth2认证的外部库,其中定义了基础认证的SecurityFilterChain:
@Bean @ConditionalOnMissingBean public AuthorizeRequestsCustomizer authorizeRequestsCustomizer( @Qualifier("basicAndFormMvc") MvcRequestMatcher.Builder mvc) { return customizer -> customizer.requestMatchers(mvc.pattern("/api/**")).authenticated().anyRequest().permitAll(); } @Order(3) @Bean("basicAndFormAuthFilter") public SecurityFilterChain filterChain( HttpSecurity http, AuthorizeRequestsCustomizer authorizeRequestsCustomizer) throws Exception { http.sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) .csrf(AbstractHttpConfigurer::disable) .cors(withDefaults()) .httpBasic(withDefaults()) .formLogin(withDefaults()) .exceptionHandling( c -> c.defaultAuthenticationEntryPointFor( customAuthenticationEntryPoint(), new AntPathRequestMatcher("/**"))) .authorizeHttpRequests(authorizeRequestsCustomizer); return http.build(); }
启动时出现冲突错误:
[ main] [ERROR] o.springframework.boot.SpringApplication: [] Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain': Cannot create inner bean '(inner bean)#7f088b5c' while setting constructor argument with key [1] at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBeanValue(BeanDefinitionValueResolver.java:421) ...(省略中间栈信息) Caused by: java.lang.IllegalArgumentException: A filter chain that matches any request [DefaultSecurityFilterChain defined as 'basicAndFormAuthFilter' in [class path resource [/BasicAndFormAuthConfig.class]] matching [any request] and having filters [DisableEncodeUrl, WebAsyncManagerIntegration, SecurityContextHolder, HeaderWriter, Cors, Logout, UsernamePasswordAuthentication, DefaultResources, DefaultLoginPageGenerating, DefaultLogoutPageGenerating, BasicAuthentication, RequestCacheAware, SecurityContextHolderAwareRequest, AnonymousAuthentication, SessionManagement, ExceptionTranslation]] has already been configured, which means that this filter chain [DefaultSecurityFilterChain defined as 'jwtSecurityFilterChain' in [class path resource [org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration$OAuth2SecurityFilterChainConfiguration.class]] matching [any request] and having filters [DisableEncodeUrl, WebAsyncManagerIntegration, SecurityContextHolder, HeaderWriter, Csrf, Logout, BearerTokenAuthentication, RequestCacheAware, SecurityContextHolderAwareRequest, AnonymousAuthentication, ExceptionTranslation, Authorization]] will never get invoked. Please use `HttpSecurity#securityMatcher` to ensure that there is only one filter chain configured for 'any request' and that the 'any request' filter chain is published last. at org.springframework.security.config.annotation.web.builders.WebSecurity.performBuild(WebSecurity.java:320) ...(省略末尾栈信息)
错误根源是外部库中OAuth2ResourceServerJwtConfiguration的内部类OAuth2SecurityFilterChainConfiguration定义的SecurityFilterChain(bean名jwtSecurityFilterChain):
@Configuration(proxyBeanMethods = false) @ConditionalOnDefaultWebSecurity static class OAuth2SecurityFilterChainConfiguration { @Bean @ConditionalOnBean(JwtDecoder.class) SecurityFilterChain jwtSecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated()); http.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(withDefaults())); return http.build(); } }
由于该配置类属于外部库无法直接修改,且常规禁用Spring Security自动配置的方案无效,需要在无@SpringBootApplication注解的自定义本地库中排除这个包私有内部配置类。
解决方案
方法1:通过@ComponentScan排除内部配置类
在自定义库的核心配置类上,利用@ComponentScan的excludeFilters指定排除目标内部类(注意内部类全类名用$连接外部类与内部类):
@Configuration @ComponentScan( excludeFilters = { @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, value = org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerJwtConfiguration.OAuth2SecurityFilterChainConfiguration.class ) } ) public class CustomSecurityConfig { // 自定义配置逻辑 }
方法2:实现BeanDefinitionRegistryPostProcessor手动移除Bean定义
通过Spring扩展点,在Bean定义注册阶段直接移除目标配置类和对应的FilterChain Bean:
@Configuration public class RemoveJwtFilterChainConfig implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // 内部类的Bean名称格式:外部类全类名.$内部类名 String configBeanName = "org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerJwtConfiguration$OAuth2SecurityFilterChainConfiguration"; if (registry.containsBeanDefinition(configBeanName)) { registry.removeBeanDefinition(configBeanName); } // 移除对应的jwtSecurityFilterChain Bean String filterChainBeanName = "jwtSecurityFilterChain"; if (registry.containsBeanDefinition(filterChainBeanName)) { registry.removeBeanDefinition(filterChainBeanName); } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 无需额外操作 } }
方法3:利用条件注解阻止自动配置生效
目标配置类带有@ConditionalOnDefaultWebSecurity注解,该注解会检查是否存在特定标记Bean。在自定义库中添加同名标记Bean,即可让原条件失效:
@Configuration public class DisableDefaultWebSecurityConfig { @Bean public DefaultWebSecurityMarker disableDefaultWebSecurityMarker() { return new DefaultWebSecurityMarker(); } // 自定义标记类,无需实现任何方法 public static class DefaultWebSecurityMarker {} }
内容的提问来源于stack exchange,提问作者wuttke
相关产品推荐
相关产品推荐

