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

Spring Boot Webflux OAuth2客户端凭证流对接Azure AD异常求助

Spring Boot 2.6.5 Webflux OAuth2 Client Credentials对接Azure AD问题解决思路

一、依赖版本校验(pom.xml)

确保核心依赖版本与Spring Boot 2.6.5匹配,避免依赖冲突:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-oauth2-jose</artifactId>
    </dependency>
</dependencies>

二、解决启动时缺失ReactiveOAuth2AuthorizedClientManager Bean的问题

Spring Boot自动配置在标准场景下会生成该Bean,若未生成,需手动配置正确的授权管理器实例,核心是指定Client Credentials模式的授权提供者:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.DefaultReactiveOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class CommonConfig {

    @Bean
    public ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager(
            ReactiveClientRegistrationRepository clientRegistrationRepository,
            ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {

        ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
                ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
                        .clientCredentials() // 明确指定Client Credentials模式
                        .build();

        DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager =
                new DefaultReactiveOAuth2AuthorizedClientManager(
                        clientRegistrationRepository, authorizedClientRepository);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }
}

三、解决serverWebExchange cannot be null异常

该异常核心原因是Webflux环境错误使用了Servlet生态的OAuth2过滤器,需替换为Webflux专属的ServerOAuth2AuthorizedClientExchangeFilterFunction,修正WebClient配置:

@Bean
public WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Filter =
            new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
    oauth2Filter.setDefaultClientRegistrationId("azure-ad"); // 对应配置文件中的客户端ID
    return WebClient.builder()
            .filter(oauth2Filter)
            .build();
}

四、application.yaml配置规范

确保Azure AD客户端信息配置准确,符合Client Credentials模式要求:

spring:
  security:
    oauth2:
      client:
        registration:
          azure-ad:
            client-id: <你的Azure AD客户端ID>
            client-secret: <你的客户端密钥>
            authorization-grant-type: client_credentials
            scope: api://<目标API资源ID>/.default # Azure AD专属格式
        provider:
          azure-ad:
            token-uri: https://login.microsoftonline.com/<你的租户ID>/oauth2/v2.0/token

五、受保护接口调用示例

Web上下文内调用(如Controller)

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@RestController
public class ApiCallController {

    private final WebClient webClient;

    public ApiCallController(WebClient webClient) {
        this.webClient = webClient;
    }

    @GetMapping("/invoke-protected-api")
    public Mono<String> invokeProtectedApi() {
        return webClient.get()
                .uri("https://<受保护API地址>")
                .retrieve()
                .bodyToMono(String.class);
    }
}

非Web上下文调用(如定时任务)

若在无ServerWebExchange的场景调用,需手动获取令牌:

import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
import reactor.core.publisher.Mono;

public class ScheduledTask {

    private final ReactiveOAuth2AuthorizedClientManager authorizedClientManager;

    public void executeTask() {
        OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("azure-ad")
                .principal("client-credentials-principal") // Client Credentials模式可自定义标识
                .build();

        authorizedClientManager.authorize(authorizeRequest)
                .flatMap(client -> {
                    String token = client.getAccessToken().getTokenValue();
                    return WebClient.create()
                            .get()
                            .uri("https://<受保护API地址>")
                            .header("Authorization", "Bearer " + token)
                            .retrieve()
                            .bodyToMono(String.class);
                })
                .subscribe(result -> {
                    // 处理返回结果
                });
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 19:07:35