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

如何生成Azure Service Principal访问令牌用于Java自动化项目

Java项目程序化获取Azure Service Principal访问令牌方案

不用依赖Azure CLI手动生成,直接通过代码实现令牌获取,可以无缝集成到BDD自动化测试的前置流程中,以下是两种经过生产验证的实现方式:

前置准备

  • 提前准备好Service Principal的三个核心参数:租户ID(tenantId)、客户端ID(clientId)、客户端密钥(clientSecret)
  • 确认该Service Principal已经被授予目标REST API的对应访问权限,否则拿到的令牌调用接口会返回403
  • 不要把敏感参数硬编码在代码中,统一从环境变量、CI/CD变量库或者加密测试配置文件读取

方式1:使用Azure官方Identity SDK(推荐)

这是稳定性最高的方案,SDK已经封装了令牌缓存、端点自动寻址、失败重试等逻辑,我自己在REST Assured搭建的BDD接口测试项目里用了一年多,没有出过鉴权相关的异常。
首先引入Maven依赖:

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-identity</artifactId>
    <version>1.11.0</version> <!-- 可替换为最新稳定版本 -->
</dependency>

核心获取令牌的代码如下:

import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenRequestContext;
import java.time.OffsetDateTime;

// 从环境变量读取配置,本地调试和流水线执行都适配
String tenantId = System.getenv("AZURE_TENANT_ID");
String clientId = System.getenv("AZURE_CLIENT_ID");
String clientSecret = System.getenv("AZURE_CLIENT_SECRET");
// 替换为你要调用的API对应的权限范围,比如调用Azure资源管理接口用下面的默认值
// 调用Graph API就换成https://graph.microsoft.com/.default,自定义API填对应的应用ID URI即可
String[] scopes = new String[]{"https://management.azure.com/.default"};

ClientSecretCredential credential = new ClientSecretCredentialBuilder()
        .tenantId(tenantId)
        .clientId(clientId)
        .clientSecret(clientSecret)
        .build();

// 同步获取访问令牌
AccessToken accessToken = credential.getTokenSync(new TokenRequestContext().addScopes(scopes));
String tokenValue = accessToken.getToken();
// 可以拿到令牌过期时间,用于本地缓存逻辑
OffsetDateTime expireTime = accessToken.getExpiresAt();

方式2:无额外依赖轻量实现(直接调用OAuth2接口)

如果不想引入Azure SDK依赖,可以直接向Azure的OAuth2令牌端点发POST请求获取令牌,适合项目依赖管控严格的场景。示例代码用JDK原生HttpClient实现,只需要项目本身自带JSON解析依赖即可:

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper; // 项目自带的JSON解析包即可

String tenantId = System.getenv("AZURE_TENANT_ID");
String clientId = System.getenv("AZURE_CLIENT_ID");
String clientSecret = System.getenv("AZURE_CLIENT_SECRET");
String scope = "https://management.azure.com/.default";
String tokenEndpoint = String.format("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantId);

// 拼接表单请求参数
String requestBody = String.format(
        "grant_type=client_credentials&client_id=%s&client_secret=%s&scope=%s",
        URLEncoder.encode(clientId, StandardCharsets.UTF_8),
        URLEncoder.encode(clientSecret, StandardCharsets.UTF_8),
        URLEncoder.encode(scope, StandardCharsets.UTF_8)
);

HttpRequest tokenRequest = HttpRequest.newBuilder()
        .uri(URI.create(tokenEndpoint))
        .header("Content-Type", "application/x-www-form-urlencoded")
        .POST(HttpRequest.BodyPublishers.ofString(requestBody))
        .build();

HttpResponse<String> response = HttpClient.newHttpClient()
        .send(tokenRequest, HttpResponse.BodyHandlers.ofString());

// 解析响应拿到令牌
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> responseMap = objectMapper.readValue(response.body(), Map.class);
String tokenValue = (String) responseMap.get("access_token");
// 响应里的expires_in是令牌有效秒数,可以自己计算过期时间做缓存
Long expireInSeconds = ((Number) responseMap.get("expires_in")).longValue();

BDD项目集成注意事项

  • 把令牌获取逻辑放在BDD框架的全局前置Hook中执行,令牌存储到测试上下文里,所有测试用例共用,不需要每个用例单独申请
  • 加一层简单的本地缓存逻辑:每次取令牌前判断是否快过期(比如距离过期时间不足5分钟),如果过期就重新申请,避免接口调用过程中令牌失效,也能减少不必要的鉴权请求提升测试执行速度
  • scope参数一定要和你要调用的目标API匹配,否则会出现拿到的令牌调用接口返回401的问题
  • CI/CD流水线执行时,只需要在流水线变量里配置好对应的三个SP参数,不需要安装或登录Azure CLI就能自动完成鉴权,完全适配自动化执行场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 22:24:16