Blazor WASM独立应用调用Graph API 24小时后提示Access token为空
问题诊断与解决方案:Blazor WASM 24小时后Graph API令牌失效及登录跳转异常
核心问题分析
- 应用运行24小时后令牌过期,
GraphAuthenticationProvider获取令牌时返回RequiresRedirect状态,但Blazor默认认证机制未自动触发跳转——自定义账户工厂可能覆盖了部分默认的令牌刷新逻辑,导致状态同步异常 - 手动处理
RequiresRedirect时未正确控制跳转触发时机,引发多次登录循环;登录完成后未同步Blazor认证状态,导致卡在“Completing login...”页面
解决方案步骤
1. 修复GraphAuthenticationProvider的令牌处理逻辑
在AuthenticateRequestAsync中,精准处理RequiresRedirect状态,避免重复跳转:
public async Task AuthenticateRequestAsync(HttpRequestMessage request) { var result = await _tokenProvider.GetAccessTokenAsync(new TokenRequestContext(scopes)); if (result.Status == TokenResultStatus.RequiresRedirect) { // 仅当前页面未在登录流程中时触发跳转 if (!_navigationManager.Uri.Contains("authentication/login")) { var returnUrl = Uri.EscapeDataString(_navigationManager.Uri); _navigationManager.NavigateTo($"authentication/login?returnUrl={returnUrl}"); return; } } else if (result.Status == TokenResultStatus.Success) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.Value); } else { throw new UnauthorizedAccessException("无法获取有效访问令牌"); } }
2. 同步自定义账户工厂的令牌状态
在CustomAccountFactory的CreateUserAsync中,确保令牌相关附加属性被正确保留到ClaimsPrincipal,避免本地存储令牌丢失:
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(RemoteUserAccount account, RemoteAuthenticationUserOptions options) { var user = await base.CreateUserAsync(account, options); if (user.Identity is ClaimsIdentity identity) { // 保留令牌相关的附加属性 var tokenProps = account.AdditionalProperties .Where(kv => kv.Key.Contains("access_token") || kv.Key.Contains("refresh_token")); foreach (var prop in tokenProps) { identity.AddClaim(new Claim(prop.Key, prop.Value.ToString())); } } return user; }
3. 优化Program.cs中的认证配置
确保启用本地存储缓存、正确配置跳转路径,并绑定自定义账户工厂:
builder.Services.AddMsalAuthentication(options => { builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication); options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/User.Read"); // 配置本地存储维护令牌 options.ProviderOptions.Cache.CacheLocation = "localStorage"; // 明确认证跳转路径 options.AuthenticationPaths.LogInPath = "/authentication/login"; options.AuthenticationPaths.LogInCallbackPath = "/authentication/login-callback"; options.AuthenticationPaths.LogOutPath = "/authentication/logout"; options.AuthenticationPaths.LogOutCallbackPath = "/authentication/logout-callback"; // 注入自定义账户工厂 options.UserOptions.AccountFactory = sp => sp.GetRequiredService<CustomAccountFactory>(); });
4. 修复登录完成后的状态同步
在Authentication.razor组件中,登录回调后强制刷新认证状态并跳转首页:
@page "/authentication/{action}" @inject AuthenticationStateProvider AuthStateProvider @inject NavigationManager NavManager @code { [Parameter] public string Action { get; set; } protected override async Task OnParametersSetAsync() { if (Action.Equals("login-callback", StringComparison.OrdinalIgnoreCase)) { // 强制刷新认证状态,同步本地令牌信息 await ((MsalAuthenticationStateProvider)AuthStateProvider).GetAuthenticationStateAsync(); // 跳转到首页或原返回页 var returnUrl = NavManager.QueryString("returnUrl") ?? "/"; NavManager.NavigateTo(returnUrl, forceLoad: true); } } }
关键注意事项
- 跳转登录时必须携带
returnUrl,否则登录后无法回到用户原来的操作页面 - 自定义账户工厂不能过滤令牌相关的附加属性,否则本地存储的令牌会丢失,导致后续认证失败
- 确保
AuthenticationService.js在index.html中被正确引用,这是Blazor WASM认证的核心前端依赖
内容的提问来源于stack exchange,提问作者Terrence Ferguson
相关产品推荐
相关产品推荐

