基于Microsoft Identity:检查访问令牌有效性并避免MsalUiRequiredException
问题解决方案
1. 在_host.cshtml展示应用前检查访问令牌有效性
你可以利用Razor页面的服务器端逻辑,在用户加载_host.cshtml时预先验证令牌状态:
- 给_host.cshtml添加页面模型文件(_Host.cshtml.cs),注入
ITokenAcquisition和IConfiguration:
public class HostModel : PageModel { private readonly ITokenAcquisition _tokenAcquisition; private readonly IConfiguration _configuration; private readonly string[] _sharepointScopes; public HostModel(ITokenAcquisition tokenAcquisition, IConfiguration configuration) { _tokenAcquisition = tokenAcquisition; _configuration = configuration; _sharepointScopes = _configuration.GetSection("SharepointScopes").Get<string[]>(); } public async Task OnGetAsync() { try { // 尝试获取令牌(MSAL会自动检查缓存,过期则用刷新令牌静默刷新) await _tokenAcquisition.GetAccessTokenForUserAsync(_sharepointScopes); } catch (MsalUiRequiredException) { // 触发重新认证,让用户重新登录获取有效令牌 await HttpContext.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme); } } }
- 在_host.cshtml顶部指定页面模型:
@page "/" @model HostModel @{ Layout = null; }
这样用户访问应用时,会先执行OnGetAsync方法验证令牌,无效则直接触发重新认证,避免后续组件调用API时出错。
2. 用户会话期间防止访问令牌过期的方法
(1)依赖MSAL自动刷新机制
MSAL默认会在访问令牌过期前,使用刷新令牌静默获取新的访问令牌。确保你的配置满足:
- 已正确配置
AddDistributedTokenCaches()(比如用Redis、SQL Server缓存),避免令牌缓存丢失导致无法刷新 - 应用在Azure AD中已获得
offline_access权限(默认EnableTokenAcquisitionToCallDownstreamApi会包含这个范围,可检查Azure AD应用的API权限)
(2)定期静默刷新令牌
在Blazor Server的全局组件(比如MainLayout.razor)中,添加定时任务,定期调用GetAccessTokenForUserAsync触发静默刷新:
@inject ITokenAcquisition TokenAcquisition @inject IConfiguration Configuration @implements IDisposable private Timer _refreshTimer; private string[] _sharepointScopes; protected override async Task OnInitializedAsync() { _sharepointScopes = Configuration.GetSection("SharepointScopes").Get<string[]>(); // 每50分钟刷新一次(访问令牌默认有效期60分钟) _refreshTimer = new Timer(async _ => await RefreshTokenAsync(), null, TimeSpan.Zero, TimeSpan.FromMinutes(50)); } private async Task RefreshTokenAsync() { try { await TokenAcquisition.GetAccessTokenForUserAsync(_sharepointScopes); } catch (MsalUiRequiredException) { // 这里可以记录日志,或者提示用户重新登录 } } public void Dispose() { _refreshTimer?.Dispose(); }
(3)优化令牌获取逻辑
在你的SharepointClientFactory中,不要用同步阻塞的.GetAwaiter().GetResult(),改用异步方式(Blazor Server支持异步事件处理):
ClientContext SharepointClientFactory() { var clientContext = new ClientContext(siteUrl); clientContext.ExecutingWebRequest += async (sender, e) => { try { string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes: effectiveScopes); e.WebRequestExecutor.RequestHeaders.Add("Authorization", $"Bearer {accessToken}"); } catch (MicrosoftIdentityWebChallengeUserException ex) { // 触发导航到登录页面 NavigationManager.NavigateTo("/MicrosoftIdentity/Account/SignIn", forceLoad: true); } }; return clientContext; }
同步阻塞可能导致MSAL无法正确处理令牌刷新流程,改用异步能确保静默刷新正常执行。
(4)调整Azure AD令牌生命周期
如果业务允许,可以在Azure AD门户中延长访问令牌的有效期(最长可设置为1天),减少过期频率:
- 进入Azure AD -> 应用注册 -> 你的应用 -> 令牌配置 -> 添加策略,设置访问令牌的生命周期
内容的提问来源于stack exchange,提问作者Liero
相关产品推荐
相关产品推荐

