You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 07:32:48