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

如何在非响应式Spring Boot中用RestTemplate+OBO实现AAD微服务调用

基于RestTemplate的Azure AD On-Behalf-Of(OBO)流程实现方案

1. 添加项目依赖

确保Maven或Gradle中引入必要的依赖,用于Azure AD身份验证及RestTemplate调用:

<!-- Spring Security OAuth2 核心依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!-- MSAL4J 用于处理Azure AD OBO流程 -->
<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>msal4j</artifactId>
    <version>1.23.0</version>
</dependency>

2. 配置Azure AD参数

在application.yml中配置微服务A的Azure AD应用信息及目标服务B的权限范围:

spring:
  security:
    oauth2:
      client:
        registration:
          azure-ad-obo:
            client-id: ${MICRO_A_CLIENT_ID} # 微服务A的Azure AD客户端ID
            client-secret: ${MICRO_A_CLIENT_SECRET} # 微服务A的客户端密钥
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            scope: openid, profile, api://{MICRO_B_CLIENT_ID}/.default # 微服务B的API权限范围
        provider:
          azure-ad-obo:
            issuer-uri: https://login.microsoftonline.com/{AZURE_TENANT_ID}/v2.0 # 替换为实际租户ID

3. 实现OBO令牌获取服务

创建服务类,从当前请求上下文提取前端令牌,通过OBO流程获取访问微服务B的令牌:

import com.microsoft.aad.msal4j.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.concurrent.CompletableFuture;

@Service
public class OboTokenService {

    @Value("${spring.security.oauth2.client.registration.azure-ad-obo.client-id}")
    private String clientId;

    @Value("${spring.security.oauth2.client.registration.azure-ad-obo.client-secret}")
    private String clientSecret;

    @Value("${spring.security.oauth2.client.provider.azure-ad-obo.issuer-uri}")
    private String authorityUri;

    @Value("${spring.security.oauth2.client.registration.azure-ad-obo.scope}")
    private String targetScope;

    public String getServiceBAccessToken() throws Exception {
        // 从Spring Security上下文获取前端传入的用户访问令牌
        OAuth2AuthenticatedPrincipal principal = (OAuth2AuthenticatedPrincipal) SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();
        String userAccessToken = principal.getAttribute("access_token");

        // 初始化ConfidentialClientApplication
        ConfidentialClientApplication client = ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromSecret(clientSecret))
                .authority(authorityUri)
                .build();

        // 构建OBO请求参数
        OnBehalfOfParameters oboParams = OnBehalfOfParameters.builder(Collections.singleton(targetScope), new UserAssertion(userAccessToken))
                .build();

        // 同步获取令牌(非响应式场景下使用get()阻塞获取结果)
        CompletableFuture<IAuthenticationResult> future = client.acquireToken(oboParams);
        IAuthenticationResult result = future.get();

        return result.accessToken();
    }
}

4. 用RestTemplate调用微服务B

创建调用服务,注入RestTemplate和OBO令牌服务,携带令牌发起请求:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class MicroServiceBClient {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private OboTokenService oboTokenService;

    public ResponseEntity<String> invokeServiceB(String serviceBEndpoint) throws Exception {
        // 获取OBO令牌
        String oboAccessToken = oboTokenService.getServiceBAccessToken();

        // 构建请求头,携带Bearer令牌
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(oboAccessToken);

        // 使用RestTemplate发起HTTP请求
        return restTemplate.exchange(
                serviceBEndpoint,
                HttpMethod.GET,
                null,
                String.class,
                headers
        );
    }
}

5. 注册RestTemplate Bean

在配置类中声明RestTemplate实例,供Spring容器管理:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

关键注意事项

  • 确保微服务A的Azure AD应用已添加并获批对微服务B应用的委派权限(需Azure AD管理员同意)
  • 前端传入的令牌必须包含scp声明,且权限范围与配置的scope匹配
  • 可扩展令牌服务添加缓存逻辑,避免重复发起OBO令牌请求,提升性能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 09:05:37