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

Blazor中如何重置HttpClientFactory的AuthorizationHeader?

解决方案

你的核心问题在于Scoped服务初始化时仅设置一次请求头,而Blazor作为单页应用,Scoped实例在组件生命周期内不会自动重建,导致登录后的新令牌无法更新到HttpClient的请求头中。以下是两种可行的解决思路:

方案一:使用Scoped DelegatingHandler 动态获取令牌

创建一个Scoped的消息处理器,在每次请求发送前从Protected Local Storage读取最新令牌,保证每次请求都使用当前有效的令牌。

1. 实现AuthTokenHandler

public class AuthTokenHandler : DelegatingHandler
{
    private readonly ProtectedLocalStorage _protectedLocalStorage;
    private readonly IServiceProvider _services;

    public AuthTokenHandler(ProtectedLocalStorage protectedLocalStorage, IServiceProvider services)
    {
        _protectedLocalStorage = protectedLocalStorage;
        _services = services;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // 每次请求前读取最新令牌
        var tokenResult = await _protectedLocalStorage.GetAsync<string>("authToken");
        if (tokenResult.Success && !string.IsNullOrEmpty(tokenResult.Value))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenResult.Value);
        }

        var response = await base.SendAsync(request, cancellationToken);

        // 处理401未授权,导航到登录页
        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            var navigationManager = _services.GetRequiredService<NavigationManager>();
            navigationManager.NavigateTo("/login", forceLoad: false);
        }

        return response;
    }
}

2. 注册Handler和HttpClient

// 注册Scoped的AuthTokenHandler(适配ProtectedLocalStorage的Scoped生命周期)
services.AddScoped<AuthTokenHandler>();

// 为每个API客户端添加该Handler
services.AddHttpClient("first-api", options =>
{
    options.BaseAddress = new Uri(first_api_uri);
})
.AddHttpMessageHandler<AuthTokenHandler>();

// 简化API服务注册,无需在注册时设置请求头
services.AddScoped<IAPIOneService, APIOneService>(context =>
{
    var httpClientFactory = context.GetRequiredService<IHttpClientFactory>();
    var httpClient = httpClientFactory.CreateClient("first-api");
    var apiClient = new APIClient(httpClient);
    return new APIOneService(apiClient);
});

这个方案无需修改业务请求逻辑,所有令牌获取和401处理都统一在Handler中完成,完全适配Blazor的生命周期规则。

方案二:登录成功后手动更新请求头

如果不想使用Handler,可以在登录成功后主动更新各API服务的HttpClient请求头,适合小型简单应用。

1. 在API服务中添加更新令牌的方法

public class APIOneService : IAPIOneService
{
    private readonly APIClient _apiClient;
    private readonly ProtectedLocalStorage _storage;

    public APIOneService(APIClient apiClient, ProtectedLocalStorage storage)
    {
        _apiClient = apiClient;
        _storage = storage;
    }

    // 手动更新认证头
    public async Task RefreshAuthToken()
    {
        var tokenResult = await _storage.GetAsync<string>("authToken");
        if (tokenResult.Success && !string.IsNullOrEmpty(tokenResult.Value))
        {
            _apiClient.HttpClient.DefaultRequestHeaders.Authorization = 
                new AuthenticationHeaderValue("Bearer", tokenResult.Value);
        }
        else
        {
            _apiClient.HttpClient.DefaultRequestHeaders.Authorization = null;
        }
    }

    // 你的业务方法...
}

2. 登录成功后调用更新方法

在登录页面的登录逻辑中,注入所有API服务并调用刷新方法:

private async Task HandleLogin()
{
    // 执行登录逻辑,获取新令牌并存入Protected Local Storage
    await _authService.Login(LoginModel);
    
    // 更新所有API服务的认证头
    await _apiOneService.RefreshAuthToken();
    await _apiTwoService.RefreshAuthToken();
    await _apiThreeService.RefreshAuthToken();

    // 导航到主页
    _navigationManager.NavigateTo("/");
}

原有方案失效原因

你在DI注册Scoped服务时仅调用一次AddHeader设置请求头,而Blazor的Scoped服务实例会伴随组件生命周期存在,不会因用户重新登录自动重建。因此旧令牌会一直保留在HttpClient的默认头中,直到组件销毁或页面刷新。

内容的提问来源于stack exchange,提问作者Leandro De Mello Fagundes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 20:00:16