基于Azure AD JWT认证,如何无会话获取Microsoft Graph令牌?
解决方案:使用Azure AD的On-Behalf-Of (OBO) 流程
你的场景正好对应Azure AD的**On-Behalf-Of (OBO)**授权流程——这是专门为中间层服务设计的,允许你的应用(已经持有用户的JWT令牌,受众为你的应用ID)代表用户向另一个资源(这里是Microsoft Graph API)请求访问令牌,全程不需要依赖会话缓存,完全符合你无状态JWT的需求。
第一步:确保Azure AD应用的配置正确
在Azure门户的应用注册中完成以下配置:
- 添加Microsoft Graph的委派权限:比如你需要获取用户数据,可以添加
User.Read.All、User.ReadBasic.All等委派权限,记得点击"授予管理员同意"(如果是租户级应用)。 - 启用客户端凭据:因为你的应用是服务端应用(Confidential Client),需要生成客户端密钥(Client Secret)或者使用证书,用于向Azure AD证明应用身份。
- 确保应用支持OBO流程:OBO流程是默认支持的,只要你的应用是Confidential Client且有正确的权限配置即可。
第二步:ASP.NET Core中的代码实现
你已经配置了JWT认证并设置SaveToken = true,这意味着用户的访问令牌会被保存到HttpContext中,我们可以直接获取它,然后用OBO流程换取Graph API的令牌。
核心代码示例
在你的控制器或服务中,注入IConfiguration,然后实现令牌换取逻辑:
using Microsoft.Identity.Client; using Microsoft.AspNetCore.Authentication; // 注入依赖 private readonly IConfiguration _config; public YourController(IConfiguration config) { _config = config; } public async Task<string> GetGraphAccessToken() { // 1. 从当前请求中获取用户的原始JWT令牌(受众为你的应用) var userAccessToken = await HttpContext.GetTokenAsync("access_token"); if (string.IsNullOrEmpty(userAccessToken)) { throw new UnauthorizedAccessException("无法获取用户的访问令牌"); } // 2. 初始化ConfidentialClientApplication(不需要TokenCache,保持无状态) var clientId = _config["AzureAd:ClientId"]; var clientSecret = _config["AzureAd:ClientSecret"]; var tenantId = _config["AzureAd:TenantId"]; var authority = $"https://login.microsoftonline.com/{tenantId}/v2.0"; var confidentialClient = ConfidentialClientApplicationBuilder .Create(clientId) .WithClientSecret(clientSecret) .WithAuthority(authority) .Build(); // 3. 执行OBO流程,获取Graph API的访问令牌 var scopes = new[] { "https://graph.microsoft.com/User.Read.All" }; // 根据你的需求调整scopes var oboParameters = new OnBehalfOfParameters(scopes, new UserAssertion(userAccessToken)); var result = await confidentialClient.AcquireTokenOnBehalfOfAsync(oboParameters); return result.AccessToken; }
配置文件(appsettings.json)示例
确保你的配置包含必要的参数:
{ "AzureAd": { "ClientId": "你的应用ID", "ClientSecret": "你的客户端密钥", "TenantId": "你的租户ID", "Instance": "https://login.microsoftonline.com/" } }
关键说明
- 无状态实现:这里没有使用任何令牌缓存(比如
SessionTokenCache),每次请求都会向Azure AD发起OBO令牌请求,完全符合你JWT无状态的要求。 - 令牌受众转换:OBO流程会将受众为你的应用的用户令牌,转换为受众为
https://graph.microsoft.com的访问令牌,该令牌可直接用于调用Graph API的用户数据接口。 - 权限要求:确保你请求的scopes已经在Azure AD应用中配置并获得了管理员同意,否则会返回权限不足的错误。
对比你之前的示例代码
你之前看到的AcquireTokenSilentAsync是用于从缓存中获取已有的令牌,适合会话式应用;而AcquireTokenOnBehalfOfAsync是专门为中间层服务设计的无状态令牌换取方式,完美匹配你的场景。
内容的提问来源于stack exchange,提问作者jokul
相关产品推荐
相关产品推荐

