如何使用Azure Managed Identity获取关联Entra ID应用的指定appID访问令牌
问题
我有一个已注册的Entra ID应用,后端依赖该应用的ClientID访问Microsoft服务(比如OAuth网页登录、Microsoft Store相关API),这些服务会通过ClientID过滤结果。之前用应用密钥生成访问令牌一切正常,但现在受租户政策限制,没法再生成应用密钥,所以改用Azure托管身份(Managed Identity)。
我已经配置了一个托管身份,并且在现有Entra ID应用的「证书和机密」下添加了关联该托管身份的联合凭据。现在能在Azure测试VM上的服务中通过托管身份获取令牌,但令牌里的appid是托管身份的ID,不是目标Entra ID应用的ClientID。
怎么把托管身份生成的令牌交换成appid为目标Entra ID应用ClientID的访问令牌?我见过相关的提及,但找不到符合需求的实际示例或文档。
当前使用的代码:
var managedClientId = "7b2a2e38-57c3-4eb8-8ec7-ad7bdbd05ac5"; var audience = "https://onestore.microsoft.com/b2b/keys/create/collections"; var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = managedClientId }); var accessToken = credential.GetToken(new TokenRequestContext(new[] { audience }));
返回的令牌结构:
{ "aud": "https://onestore.microsoft.com/b2b/keys/create/collections", "iat": 1752781126, "nbf": 1752781126, "exp": 1752867826, "appid": "7b2a2e38-57c3-4eb8-8ec7-ad7bdbd05ac5", ... }
解决方案
你需要通过OAuth 2.0令牌交换流程,用托管身份的令牌获取目标Entra ID应用的访问令牌,核心是调用Entra ID的令牌端点,用托管身份的JWT作为assertion参数。
核心步骤
- 获取托管身份的身份令牌:先拿到一个以Entra ID令牌端点为受众的托管身份令牌,用于向Entra ID证明自身身份。
- 调用令牌交换端点:用第一步的令牌作为断言,请求Entra ID返回目标应用的访问令牌,此时返回的令牌
appid会是目标Entra ID应用的ClientID。
代码实现
using System.Net.Http.Headers; using System.Text; using System.Text.Json; // 配置参数 string tenantId = "你的租户ID"; string managedIdentityClientId = "7b2a2e38-57c3-4eb8-8ec7-ad7bdbd05ac5"; string targetAppClientId = "目标Entra ID应用的ClientID"; string targetAudience = "https://onestore.microsoft.com/b2b/keys/create/collections"; // 1. 获取托管身份的JWT(受众指向Entra ID令牌端点) var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = managedIdentityClientId }); var miToken = credential.GetToken(new TokenRequestContext(new[] { $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token" })).Token; // 2. 发起令牌交换请求 var httpClient = new HttpClient(); var tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token"; var requestBody = new Dictionary<string, string> { ["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer", ["client_id"] = managedIdentityClientId, ["assertion"] = miToken, ["scope"] = $"{targetAppClientId}/.default", ["requested_token_use"] = "on_behalf_of", ["audience"] = targetAudience }; var content = new FormUrlEncodedContent(requestBody); var response = await httpClient.PostAsync(tokenEndpoint, content); response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync(); var tokenResult = JsonSerializer.Deserialize<JsonElement>(responseJson); string targetAccessToken = tokenResult.GetProperty("access_token").GetString();
关键注意事项
- 确认目标Entra ID应用的联合凭据配置正确:受众设为托管身份的ClientID,实体类型选「Managed identity」,实体ID填写托管身份的ObjectID或ClientID。
- 托管身份必须被授予目标Entra ID应用的对应应用权限(根据目标服务需求配置),否则交换时会返回权限不足的错误。
- 交换后的访问令牌
appid字段会匹配目标Entra ID应用的ClientID,满足服务的过滤要求。
内容的提问来源于stack exchange,提问作者Cameron
相关产品推荐
相关产品推荐

