You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin Spring Boot中WebClient注入为null,如何加载OAuth配置?

问题

我通过ReactiveClientRegistrationRepository为WebClient配置了OAuthClientConfiguration,但自动注入WebClient Bean时返回null,无法加载配置。

配置类代码:

@Configuration
class OAuthClientConfiguration {
    @Bean
    fun clientRegistrations(
        @Value("\${spring.security.oauth2.client.provider.okta.access-token-url}") access_token: String?,
        @Value("\${spring.security.oauth2.client.registration.okta.client-id}") client_id: String?,
        @Value("\${spring.security.oauth2.client.registration.okta.client-secret}") client_secret: String?,
        @Value("\${spring.security.oauth2.client.registration.okta.scope}") scope: String?,
        @Value("\${spring.security.oauth2.client.registration.okta.authorization-grant-type}") authorizationGrantType: String?
    ): ReactiveClientRegistrationRepository? {
        val registration = ClientRegistration
            .withRegistrationId("okta")
            .tokenUri(access_token)
            .clientId(client_id)
            .clientSecret(client_secret)
            .scope(scope)
            .authorizationGrantType(AuthorizationGrantType(authorizationGrantType))
            .build()
        return InMemoryReactiveClientRegistrationRepository(registration)
    }

    @Bean
    fun webClient(clientRegistrations: ReactiveClientRegistrationRepository?): WebClient? {
        val clientService = InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations)
        val authorizedClientManager =
            AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, clientService)
        val oauth = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
        oauth.setDefaultClientRegistrationId("okta")
        return WebClient.builder()
            .filter(oauth)
            .build()
    }
}

调用代码:

@Autowired
private var webClient: WebClient? = null


fun getAccessToken(): String? {
    return webClient?.post()
        ?.retrieve()
        ?.bodyToFlux(String::class.java)
        ?.onErrorMap { e: Throwable? -> Exception("message", e) }
        ?.blockLast();
}

希望创建带有该配置的WebClient,并在初始化时完成注入。


解决方案

1. 消除配置类中的空值风险

@Value注入的参数若配置缺失会返回null,直接用于构建ClientRegistration会导致Bean创建失败,进而WebClient无法注册。需做以下调整:

  • 移除参数的可空标记,确保配置项必须存在(若允许配置缺失,可添加默认值)
  • 拆分多scope字符串为数组,适配ClientRegistration的scope方法要求

修改后的clientRegistrations方法:

@Bean
fun clientRegistrations(
    @Value("\${spring.security.oauth2.client.provider.okta.access-token-url}") accessTokenUrl: String,
    @Value("\${spring.security.oauth2.client.registration.okta.client-id}") clientId: String,
    @Value("\${spring.security.oauth2.client.registration.okta.client-secret}") clientSecret: String,
    @Value("\${spring.security.oauth2.client.registration.okta.scope}") scope: String,
    @Value("\${spring.security.oauth2.client.registration.okta.authorization-grant-type}") authorizationGrantType: String
): ReactiveClientRegistrationRepository {
    val registration = ClientRegistration
        .withRegistrationId("okta")
        .tokenUri(accessTokenUrl)
        .clientId(clientId)
        .clientSecret(clientSecret)
        .scope(*scope.split(",").toTypedArray())
        .authorizationGrantType(AuthorizationGrantType(authorizationGrantType))
        .build()
    return InMemoryReactiveClientRegistrationRepository(registration)
}

2. 确保WebClient Bean非空返回

Spring容器不会注册返回null的Bean,需将WebClient及依赖的ReactiveClientRegistrationRepository的返回类型改为非空:

修改后的webClient方法:

@Bean
fun webClient(clientRegistrations: ReactiveClientRegistrationRepository): WebClient {
    val clientService = InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations)
    val authorizedClientManager = AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
        clientRegistrations, clientService
    )
    val oauthFilter = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
    oauthFilter.setDefaultClientRegistrationId("okta")
    
    return WebClient.builder()
        .filter(oauthFilter)
        .build()
}

3. 改用构造注入避免空值

字段注入@Autowired可能在Bean未初始化完成时出现null,改用构造注入更可靠:

修改调用类:

class YourService(private val webClient: WebClient) {

    fun getTargetData(): String? {
        // 调用目标接口,OAuth过滤器会自动添加token到请求头
        return webClient.get()
            .uri("https://your-target-api.com/data")
            .retrieve()
            .bodyToFlux(String::class.java)
            .onErrorMap { Exception("请求失败", it) }
            .blockLast()
    }
}

4. 修正token获取逻辑

原代码中webClient.post()未指定请求URL,且ServerOAuth2AuthorizedClientExchangeFilterFunction会自动处理token的获取与刷新,无需手动调用token接口。若需直接获取token,可调整为:

fun getAccessToken(): Mono<OAuth2AccessToken> {
    val authorizedClientManager = AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
        clientRegistrations, InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations)
    )
    return authorizedClientManager.authorize(
        OAuth2AuthorizeRequest.withClientRegistrationId("okta")
            .principal(AnonymousAuthenticationToken("anonymous", "anonymous", emptyList()))
            .build()
    ).map { it.accessToken }
}

内容的提问来源于stack exchange,提问作者Hamza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 05:15:30