Blazor WASM如何优雅捕获未授权响应并跳转至登录页?
在Blazor中全局捕获未授权HTTP响应并跳转登录页的方案
核心思路:通过HttpClient委托处理器全局拦截响应
由于你的客户端服务均基于HttpClient发起请求,最优雅的解决方案是给HttpClient添加自定义DelegatingHandler,统一拦截所有HTTP响应,识别401未授权状态后执行跳转逻辑,无需修改现有服务代码。
步骤1:创建自定义DelegatingHandler
该处理器会在请求完成后检查响应状态,集成token刷新逻辑(如果你的refresh token机制已实现),失败则跳转登录页:
public class AuthMessageHandler : DelegatingHandler { private readonly NavigationManager _navigationManager; private readonly IAuthService _authService; // 用于处理token的自定义服务 public AuthMessageHandler(NavigationManager navigationManager, IAuthService authService) { _navigationManager = navigationManager; _authService = authService; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var response = await base.SendAsync(request, cancellationToken); if (response.StatusCode == HttpStatusCode.Unauthorized) { // 尝试刷新token var refreshSuccess = await _authService.TryRefreshTokenAsync(); if (refreshSuccess) { // 刷新成功后重新发起原请求 var newToken = await _authService.GetCurrentAccessTokenAsync(); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", newToken); response = await base.SendAsync(request, cancellationToken); } else { // 刷新失败,清除本地认证数据并跳转登录页 await _authService.ClearAuthDataAsync(); // 避免重复跳转登录页 if (!_navigationManager.Uri.EndsWith("/login", StringComparison.OrdinalIgnoreCase)) { _navigationManager.NavigateTo("/login", forceLoad: true); } } } return response; } }
步骤2:注册自定义Handler与HttpClient
在Program.cs中注册处理器,并关联到你的API客户端:
// 注册自定义处理器(Blazor WebAssembly用AddScoped,Server可根据需求用AddTransient/Scoped) builder.Services.AddScoped<AuthMessageHandler>(); // 给API客户端添加拦截器 builder.Services.AddHttpClient<IMyApiClient, MyApiClient>(client => { client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress); }) .AddHttpMessageHandler<AuthMessageHandler>();
步骤3:补充AuthService核心逻辑
你的IAuthService需要实现token刷新、获取、清除的基础功能,示例如下:
public interface IAuthService { Task<bool> TryRefreshTokenAsync(); Task<string> GetCurrentAccessTokenAsync(); Task ClearAuthDataAsync(); } public class AuthService : IAuthService { private readonly HttpClient _httpClient; private readonly ILocalStorageService _localStorage; // 用于存储token的本地服务 public AuthService(HttpClient httpClient, ILocalStorageService localStorage) { _httpClient = httpClient; _localStorage = localStorage; } public async Task<bool> TryRefreshTokenAsync() { var refreshToken = await _localStorage.GetItemAsync<string>("refreshToken"); if (string.IsNullOrEmpty(refreshToken)) return false; try { var response = await _httpClient.PostAsJsonAsync("/api/auth/refresh", new { RefreshToken = refreshToken }); if (!response.IsSuccessStatusCode) return false; var newTokens = await response.Content.ReadFromJsonAsync<TokenResponse>(); await _localStorage.SetItemAsync("accessToken", newTokens.AccessToken); await _localStorage.SetItemAsync("refreshToken", newTokens.RefreshToken); return true; } catch { return false; } } public async Task<string> GetCurrentAccessTokenAsync() { return await _localStorage.GetItemAsync<string>("accessToken"); } public async Task ClearAuthDataAsync() { await _localStorage.RemoveItemAsync("accessToken"); await _localStorage.RemoveItemAsync("refreshToken"); } } // 用于接收刷新token返回数据的模型 public class TokenResponse { public string AccessToken { get; set; } public string RefreshToken { get; set; } }
额外注意事项
- 避免循环跳转:检查当前页面是否为登录页,防止重复触发跳转逻辑。
- 适配Blazor模式:Server模式下
NavigateTo的forceLoad参数可根据需求调整;WebAssembly模式下一般需要开启forceLoad: true确保页面重新加载。 - 异常防护:在token刷新逻辑中捕获网络异常等情况,避免程序崩溃。
- 零侵入修改:所有现有API客户端会自动继承拦截逻辑,无需修改原有服务的请求代码。
内容的提问来源于stack exchange,提问作者AlgoRythm
相关产品推荐
相关产品推荐

