Hosted Blazor WASM对接Azure AD B2C时OnTokenValidated事件不触发如何解决
问题原因
OnMessageReceived是JWT验证流程的最早阶段,仅完成了请求头中Token的提取,还未执行Token有效性校验,所以Principal必然为null,无法获取用户声明。OnTokenValidated仅在Token校验完全通过后才会触发,未触发的核心原因通常是:配置写在Blazor WASM客户端项目(该配置仅适用于服务端API的JWT校验场景)、请求受保护接口时未携带有效Access Token、Token校验不通过(如受众、签名、有效期错误等)。
可行解决方案
步骤1:确认配置位置
JWT身份验证相关配置必须写在Hosted Blazor的后端API项目中,不要写到Blazor WASM客户端项目里。
步骤2:补充校验失败日志排查问题
在原有配置基础上增加OnAuthenticationFailed事件,确认是否是Token校验失败导致OnTokenValidated未触发:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi( JwtBearerOptions => { JwtBearerOptions.Events ??= new JwtBearerEvents(); // 新增校验失败日志,排查具体错误原因 JwtBearerOptions.Events.OnAuthenticationFailed = context => { // 可替换为你项目的日志组件输出错误 Console.WriteLine($"Token校验失败:{context.Exception.Message}"); return Task.CompletedTask; }; JwtBearerOptions.Events.OnTokenValidated += OnTokenValidatedCallbackFunc; }, configureMicrosoftIdentityOptions => { Configuration.Bind("AzureAdB2C", configureMicrosoftIdentityOptions); });
步骤3:触发OnTokenValidated的正确方式
该事件仅会在请求携带有效Token访问加了[Authorize]属性的受保护接口时触发,你可以在前端登录成功后主动调用后端初始化接口触发该流程:
后端新增初始化接口
[ApiController] [Route("api/[controller]")] [Authorize] public class AuthInitController : ControllerBase { private readonly AppDbContext _dbContext; public AuthInitController(AppDbContext dbContext) { _dbContext = dbContext; } [HttpGet("status")] public async Task<IActionResult> GetInitStatus() { var userId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.AdB2cId == userId); // 也可以在这里直接写新用户创建逻辑,比在OnTokenValidated中处理更灵活 if (user == null) { user = new AppUser { AdB2cId = userId, Email = User.FindFirst(System.Security.Claims.ClaimTypes.Email)?.Value, DisplayName = User.FindFirst("name")?.Value, IsProfileCompleted = false }; _dbContext.Users.Add(user); await _dbContext.SaveChangesAsync(); } return Ok(new { NeedProfileSetup = !user.IsProfileCompleted }); } }
前端登录后调用接口判断跳转
在Blazor WASM的登录后页面(如MainLayout、Authentication回调页)添加如下逻辑:
@inject IAccessTokenProvider TokenProvider @inject HttpClient HttpClient @inject NavigationManager NavManager protected override async Task OnInitializedAsync() { var tokenResult = await TokenProvider.RequestAccessToken(); if (tokenResult.TryGetToken(out var token)) { HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token.Value); var initStatus = await HttpClient.GetFromJsonAsync<InitStatusDto>("api/AuthInit/status"); // 新用户未完成配置直接跳转到配置页 if (initStatus.NeedProfileSetup) { NavManager.NavigateTo("/profile-setup"); } } }
内容的提问来源于stack exchange,提问作者Alberto Passalacqua
相关产品推荐
相关产品推荐

