Microsoft Entra ID应用用户模拟:跨应用及Azure DevOps API访问问题
问题分析与解决方案
核心问题
你拿到的访问令牌受众(aud声明)是App1的客户端ID,而Azure DevOps API只接受受众为自身固定资源ID(499b84ac-1321-427f-aa17-267ca6975798)的令牌,所以直接传递App1的令牌会被拒绝并返回登录页面。另外,你需要使用**OAuth 2.0代表流(OBO Flow)**来实现后端API代表用户调用Azure DevOps API,这是你之前遗漏的核心流程。
必要配置检查
- 确认App1添加的Azure DevOps权限是委托权限下的
user_impersonation,而非应用权限。代表用户操作必须用委托权限,应用权限是应用自身身份的操作,不关联用户身份。 - 确保该委托权限已获得管理员同意。后端API场景下,管理员同意是强制要求,否则无法获取关联用户的有效令牌。
正确实现流程
你需要将用户提供给App1的令牌兑换为针对Azure DevOps的访问令牌,具体步骤如下:
1. 获取用户针对App1的有效令牌
当用户访问App1时,App1需先获取用户的访问令牌——该令牌的受众是App1,且包含scp声明(表示用户授予App1的委托权限)。这个令牌通常来自前端客户端的身份验证结果,或其他调用App1的客户端传递的用户令牌。
2. 使用OBO流兑换Azure DevOps令牌
利用Azure AD的代表流,App1以自身托管身份(无需客户端密钥)为身份,结合用户的令牌,向Azure AD请求针对Azure DevOps资源的访问令牌。
代码示例(Python,基于azure-identity)
from azure.identity import OnBehalfOfCredential import requests # 用户访问App1时提供的访问令牌 user_access_token = "<user-access-token-for-app1>" # 初始化代表流凭据 obo_credential = OnBehalfOfCredential( tenant_id="<你的租户ID>", client_id="<App1的客户端ID>", client_credential=None, # 托管身份无需客户端密钥,自动使用托管身份完成身份验证 user_assertion=user_access_token ) # 请求Azure DevOps的访问令牌,资源ID固定为499b84ac-1321-427f-aa17-267ca6975798 devops_token = obo_credential.get_token("499b84ac-1321-427f-aa17-267ca6975798/.default") # 调用Azure DevOps API示例 headers = { "Authorization": f"Bearer {devops_token.token}", "Content-Type": "application/json" } response = requests.get( "https://dev.azure.com/<你的组织名>/_apis/projects?api-version=7.1-preview.4", headers=headers ) print(response.json())
关键注意事项
- 不要使用
az account get-access-token --resource "api://<app1-client-id>"获取的令牌,该令牌仅适用于访问App1,无法直接用于Azure DevOps。 - 托管身份仅用于App1自身与Azure服务(如KeyVault)的交互,代表用户调用Azure DevOps时,核心依赖OBO流,托管身份在这里作为App1的身份发起令牌兑换请求。
- 用户的令牌必须有效且包含
scp声明,否则OBO流会执行失败。
内容的提问来源于stack exchange,提问作者captainjack42
相关产品推荐
相关产品推荐

