Azure认证获取的访问令牌如何刷新?避免用户频繁登录
问题描述
我在Azure App Service中有一段HomeController初始化代码如下:
public HomeController(ILogger<HomeController> logger, GraphServiceClient graphServiceClient, ITokenAcquisition tokenAcquisition) { var task = Task.Run(async () => await tokenAcquisition.GetAuthenticationResultForUserAsync(new[] { "some.allowed.scope" })); var context = task.Result; var accessToken = context.AccessToken; var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); client.DefaultRequestHeaders.Add("FeatureFlag", "00000004"); var newGraphClient = new GraphServiceClient(client); }
当前访问令牌可正常用于GraphServiceClient,但令牌约1小时后过期。我的服务需要在不打扰用户的情况下定期操作Azure账户,请问如何避免用户频繁登录?
解决方案
1. 利用刷新令牌自动续期访问令牌
通过GetAuthenticationResultForUserAsync获取的AuthenticationResult包含刷新令牌(Refresh Token),有效期通常为90天,可用于在访问令牌过期时自动获取新令牌,无需用户交互。核心要点:
- 必须确保申请的权限包含
offline_access,否则无法获取刷新令牌 - 持久化加密存储刷新令牌(如Azure SQL、Cosmos DB或加密配置),关联用户标识
- 借助MSAL的自动刷新机制,无需手动处理令牌过期逻辑
修改后的异步规范代码示例(避免构造函数同步阻塞):
private readonly ITokenAcquisition _tokenAcquisition; private readonly GraphServiceClient _graphServiceClient; public HomeController(ILogger<HomeController> logger, GraphServiceClient graphServiceClient, ITokenAcquisition tokenAcquisition) { _tokenAcquisition = tokenAcquisition; _graphServiceClient = graphServiceClient; } public async Task<IActionResult> ExecuteBackgroundTask() { try { // MSAL会自动检查令牌有效期,过期则用刷新令牌获取新令牌 var authResult = await _tokenAcquisition.GetAuthenticationResultForUserAsync(new[] { "some.allowed.scope", "offline_access" }); var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken); httpClient.DefaultRequestHeaders.Add("FeatureFlag", "00000004"); var graphClient = new GraphServiceClient(httpClient); // 执行你的Graph操作 await graphClient.Me.Messages.Request().GetAsync(); } catch (MsalUiRequiredException) { // 刷新令牌也已过期,需引导用户重新登录 return Challenge(); } return Ok(); }
2. 结合后台服务处理定期任务
若需在用户不活跃时执行周期性操作,使用**ASP.NET Core后台服务(IHostedService)**配合持久化刷新令牌:
- 用户登录时,将刷新令牌与用户ID关联加密存储
- 后台服务定时读取待处理用户的刷新令牌,调用MSAL获取有效访问令牌
- 执行Graph操作后,更新存储的刷新令牌(每次刷新可能返回新的刷新令牌)
3. 切换至客户端凭据流(无用户上下文场景)
如果操作无需用户个人上下文(如访问租户级资源),直接使用应用身份获取令牌,完全无需用户参与:
- 在Azure AD应用注册中添加应用权限(而非委托权限)并授予管理员同意
- 使用
ConfidentialClientApplication获取应用令牌:
var clientId = "你的应用ID"; var clientSecret = "你的应用密钥"; var tenantId = "你的租户ID"; var scopes = new[] { "https://graph.microsoft.com/.default" }; var app = ConfidentialClientApplicationBuilder .Create(clientId) .WithClientSecret(clientSecret) .WithTenantId(tenantId) .Build(); var authResult = await app.AcquireTokenForClient(scopes).ExecuteAsync(); var graphClient = new GraphServiceClient( new DelegateAuthenticationProvider(request => { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken); return Task.CompletedTask; }));
此方式令牌有效期同样为1小时,但MSAL会自动刷新,且全程无需用户交互。
关键注意事项
- 令牌缓存持久化:实现
ITokenCacheProvider来持久化MSAL令牌缓存,减少重复请求 - 异步规范:禁止在构造函数中使用
Task.Run+.Result,避免线程死锁,改用异步Action或初始化方法 - 安全存储:刷新令牌为敏感信息,必须加密存储,禁止明文保存
- 权限管理:根据实际场景选择委托权限(用户上下文)或应用权限(无用户上下文)
内容的提问来源于stack exchange,提问作者OGP
相关产品推荐
相关产品推荐

