如何获取Azure用户访问持久令牌,在WebJob中离线访问用户邮箱
问题根因分析
你遇到的GetAccountAsync返回null是因为两个核心原因:
- 前端使用的
PublicClientApplication(公共客户端)和后端WebJob使用的ConfidentialClientApplication(机密客户端)是完全隔离的MSAL实例,二者的本地令牌缓存、账号信息默认不会跨实例、跨环境同步,后端机密客户端的本地缓存为空,自然查不到对应账号。 GetAccountAsync的作用仅为从当前MSAL客户端实例的本地缓存中检索已完成身份验证的账号信息,本身不具备跨实例拉取账号的能力。
解决方案
你已经在前端请求了offline_access权限,这刚好是实现离线访问用户资源的核心权限,不需要申请应用权限,按以下流程实现即可:
- 前端调用
acquireTokenPopup拿到授权响应后,将响应中的refresh_token、用户账号标识、租户ID等信息加密后传输到后端,存储到你的业务数据库中(refresh_token属于高敏感信息,必须加密存储,禁止明文落盘)。 - WebJob中不再调用
GetAccountAsync查询账号,直接使用存储的refresh_token兑换有效的access_token调用Microsoft Graph即可,每次兑换新token时MSAL会返回新的refresh_token,同步更新数据库中的存储值即可实现长期有效访问。
代码示例
前端获取refresh_token后传输到后端的逻辑补充
mailApp.acquireTokenPopup(accessTokenRequest).then(accessTokenResponse => { // 提取refresh_token、账号信息 const refreshToken = accessTokenResponse.refreshToken; const accountId = accessTokenResponse.account.homeAccountId; // 调用后端接口将上述信息加密上传存储 // ...你的业务逻辑 })
WebJob中兑换access_token的代码
var app = ConfidentialClientApplicationBuilder.Create(ClientId) .WithClientSecret(Secret) .WithTenantId(Tenant) .Build(); // 从数据库中读取对应用户加密存储的refresh_token string savedRefreshToken = GetRefreshTokenFromDB(accountId); var scopes = new[] { "User.Read", "MailboxSettings.Read", "Mail.ReadWrite" }; var tokenResult = await app.AcquireTokenByRefreshToken(scopes, savedRefreshToken) .ExecuteAsync(); // 拿到有效的access_token调用Graph即可 string accessToken = tokenResult.AccessToken; // 兑换成功后将新的refresh_token更新到数据库 UpdateRefreshTokenToDB(accountId, tokenResult.RefreshToken);
注意事项
- refresh_token的默认有效期最长可达90天,每次兑换新token后都会生成新的refresh_token并重置有效期,只要你每次更新存储的refresh_token,且用户未主动撤销对你应用的授权,就可以长期正常访问。
- 禁止将refresh_token暴露到前端、日志等非安全区域,存储和传输过程必须做加密处理。
内容的提问来源于stack exchange,提问作者SpitefulG
相关产品推荐
相关产品推荐

