微服务实现SecurityFilterChain后springSecurityFilterChain Bean注册失败
springSecurityFilterChain Bean重复定义错误排查与解决
问题现象
实现SecurityFilterChain后启动微服务时触发报错:
无法注册类路径资源[org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration$WebSecurityConfiguration.class]中定义的bean 'springSecurityFilterChain',该名称的bean已在类路径资源[org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]中定义,且不允许覆盖。
根本原因
项目同时引入了Servlet栈Spring Security和Reactive栈Spring Security相关组件,导致Bean定义冲突:
- 项目依赖
spring-boot-starter-webflux(响应式Web框架),会自动引入Reactive版本的Security配置组件 - 自定义的
SecurityConfig使用了Servlet栈的HttpSecurity和SecurityFilterChain(来自org.springframework.security.web包),触发了Servlet栈的WebSecurityConfiguration自动配置 - 两个配置体系都会创建名为
springSecurityFilterChain的核心Bean,最终导致重复定义冲突
解决方案
因为项目基于WebFlux(响应式),需要切换为Reactive版本的Security配置:
1. 修改SecurityConfig配置类
替换Servlet栈的Security API为Reactive版本:
package com.mservice.rating.service.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.web.server.SecurityWebFilterChain; @Configuration @EnableReactiveMethodSecurity(prePostEnabled = true) public class SecurityConfig { @Bean public SecurityWebFilterChain filterChain(ServerHttpSecurity security) { security .authorizeExchange() .anyExchange() .authenticated() .and() .oauth2ResourceServer() .jwt(); return security.build(); } }
- 用
ServerHttpSecurity替换Servlet栈的HttpSecurity - 用
SecurityWebFilterChain替换SecurityFilterChain - 用
@EnableReactiveMethodSecurity替换@EnableGlobalMethodSecurity(响应式环境下的方法级安全注解) - 移除
@EnableWebSecurity(该注解仅适用于Servlet环境)
2. (可选)排除冲突的自动配置
如果修改后仍存在冲突,可以在启动类添加注解排除Servlet栈的Security自动配置:
@SpringBootApplication(exclude = {org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.class})
项目原始配置
SecurityConfig.java
package com.mservice.rating.service.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity security) throws Exception { security .authorizeHttpRequests() .anyRequest() .authenticated() .and() .oauth2ResourceServer() .jwt(); return security.build(); } }
Pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.mservice.rating.service</groupId> <artifactId>RatingService</artifactId> <version>0.0.1-SNAPSHOT</version> <name>RatingService</name> <description>This is rating service to store rating related informations</description> <properties> <java.version>17</java.version> <spring-cloud.version>2022.0.1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>com.okta.spring</groupId> <artifactId>okta-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
Application.yml
server: port: 8083 spring: application: name: RATING-SERVICE data: mongodb: uri: mongodb://localhost:27017 database: microservices config: import: optional:configserver:http://localhost:8085 okta: oauth2: issuer: https://dev-23279260.okta.com/oauth2/default audience: api://default
内容的提问来源于stack exchange,提问作者Vishal Srivastava
相关产品推荐
相关产品推荐

