仅配置客户端凭证时ReactiveOAuth2AuthorizedClientManager未自动配置
我创建了一个基于WebFlux的极简响应式应用,引入OAuth2客户端starter并配置了provider和registration属性,但ReactiveOAuth2AuthorizedClientManager未被自动配置。
POM文件
<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.2.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.c4-soft.springaddons.sample</groupId> <artifactId>http-exchange-reactive</artifactId> <version>0.0.1-SNAPSHOT</version> <description>Resource server with custom authentication manager</description> <properties> <java.version>21</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </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> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
应用配置
keycloak-base-uri: https://localhost:8443/auth issuer: ${keycloak-base-uri}/realms/master keycloak-admin-api-consumer-secret: change-me spring: security: oauth2: client: provider: keycloak: issuer-uri: ${issuer} registration: backend-with-client-credentials: provider: keycloak authorization-grant-type: client_credentials client-id: keycloak-admin-api-consumer client-secret: ${keycloak-admin-api-consumer-secret} scope: openid
复现代码
@SpringBootApplication public class HttpClientReactiveApplication { public static void main(String[] args) { SpringApplication.run(HttpClientReactiveApplication.class, args); } @Bean Converter<String, String> failToInject(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) { return source -> source; } }
启动错误日志
2024-02-19T15:01:51.575-10:00[0;39m [32m INFO[0;39m [35m21168[0;39m [2m---[0;39m [2m[ main][0;39m [2m[0;39m[36mc.c.o.HttpClientReactiveApplication [0;39m [2m:[0;39m Starting HttpClientReactiveApplication using Java 21 with PID 21168 (D:\workspaces\libs\http-client-reactive\target\classes started by ch4mp in D:\workspaces\libs\http-client-reactive) [2m2024-02-19T15:01:51.577-10:00[0;39m [32m INFO[0;39m [35m21168[0;39m [2m---[0;39m [2m[ main][0;39m [2m[0;39m[36mc.c.o.HttpClientReactiveApplication [0;39m [2m:[0;39m No active profile set, falling back to 1 default profile: "default" [2m2024-02-19T15:01:52.949-10:00[0;39m [33m WARN[0;39m [35m21168[0;39m [2m---[0;39m [2m[ main][0;39m [2m[0;39m[36monfigReactiveWebServerApplicationContext[0;39m [2m:[0;39m Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'failToInject' defined in com.c4soft.openfeign.HttpClientReactiveApplication: Unsatisfied dependency expressed through method 'failToInject' parameter 0: No qualifying bean of type 'org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} [2m2024-02-19T15:01:52.966-10:00[0;39m [32m INFO[0;39m [35m21168[0;39m [2m---[0;39m [2m[ main][0;39m [2m[0;39m[36m.s.b.a.l.ConditionEvaluationReportLogger[0;39m [2m:[0;39m Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. [2m2024-02-19T15:01:52.995-10:00[0;39m [31mERROR[0;39m [35m21168[0;39m [2m---[0;39m [2m[ main][0;39m [2m[0;39m[36mo.s.b.d.LoggingFailureAnalysisReporter [0;39m [2m:[0;39m *************************** APPLICATION FAILED TO START *************************** Description: Parameter 0 of method failToInject in com.c4soft.openfeign.HttpClientReactiveApplication required a bean of type 'org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager' that could not be found. Action: Consider defining a bean of type 'org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager' in your configuration.
问题原因及解决方案
核心原因
你同时引入了spring-boot-starter-oauth2-resource-server和spring-boot-starter-oauth2-client依赖,Spring Security的自动配置逻辑中,资源服务器模式的优先级高于OAuth2客户端模式。当应用同时包含这两种角色时,自动配置会优先启用资源服务器相关组件,而OAuth2客户端侧的ReactiveOAuth2AuthorizedClientManager等Bean不会被自动初始化。
另外,ReactiveOAuth2AuthorizedClientManager的自动配置类生效条件之一是:上下文未被资源服务器的配置逻辑覆盖,而你的场景中资源服务器配置抢占了初始化优先级。
解决方案
方案1:手动配置ReactiveOAuth2AuthorizedClientManager
直接在配置类中声明该Bean,适配客户端凭证模式:
@Bean public ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager( ReactiveClientRegistrationRepository clientRegistrationRepository, ServerOAuth2AuthorizedClientService authorizedClientService) { ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder() .clientCredentials() .build(); AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager( clientRegistrationRepository, authorizedClientService); authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); return authorizedClientManager; }
方案2:同时启用资源服务器和客户端配置
自定义SecurityFilterChain,明确同时配置两种模式的规则,触发Spring Security初始化双方的组件:
@Bean public SecurityFilterChain securityFilterChain(ServerHttpSecurity http) throws Exception { http .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())) .oauth2Client(Customizer.withDefaults()); return http.build(); }
内容的提问来源于stack exchange,提问作者ch4mp
相关产品推荐
相关产品推荐

