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

如何为Blazor WASM自动生成的OpenAPI代码添加认证令牌

解决方案:给Blazor WASM自动生成的OpenAPI客户端添加JWT认证头

要实现每次请求自动注入JWT令牌,同时配合自动生成的CustomApi客户端,你可以通过自定义DelegatingHandler拦截请求的方式实现,既不用修改自动生成的代码,也能动态获取最新令牌。

步骤1:创建自定义认证请求拦截器

这个Handler会在每次请求发送前,从AuthenticationStateProvider(或直接从LocalStorage)获取令牌并添加到请求头:

using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class AuthHeaderHandler : DelegatingHandler
{
    private readonly AuthenticationStateProvider _authStateProvider;

    public AuthHeaderHandler(AuthenticationStateProvider authStateProvider)
    {
        _authStateProvider = authStateProvider;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // 获取当前认证状态
        var authState = await _authStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        // 如果用户已认证,添加Bearer令牌
        if (user.Identity is { IsAuthenticated: true })
        {
            // 这里的Claim名称要和你存储JWT时的字段匹配,比如"access_token"或"jwt"
            var token = user.FindFirst("access_token")?.Value;
            if (!string.IsNullOrEmpty(token))
            {
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
            }
        }

        // 继续发送请求
        return await base.SendAsync(request, cancellationToken);
    }
}

如果你的令牌是直接存在LocalStorage而非通过AuthenticationStateProvider暴露的,可以改用Blazored.LocalStorage直接读取:

using Blazored.LocalStorage;
// ...
public class AuthHeaderHandler : DelegatingHandler
{
    private readonly ILocalStorageService _localStorage;

    public AuthHeaderHandler(ILocalStorageService localStorage)
    {
        _localStorage = localStorage;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var token = await _localStorage.GetItemAsStringAsync("jwt_token"); // 替换为你的LocalStorage键名
        if (!string.IsNullOrEmpty(token))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        }
        return await base.SendAsync(request, cancellationToken);
    }
}

步骤2:在Program.cs中注册服务

修改Program.cs的服务注册逻辑,将自定义Handler、HttpClient和自动生成的CustomApi关联起来:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");

// 1. 注册自定义认证Handler(Scoped生命周期,确保每次请求能获取最新令牌)
builder.Services.AddScoped<AuthHeaderHandler>();

// 2. 注册带认证拦截的HttpClient
builder.Services.AddScoped(sp =>
{
    var authHandler = sp.GetRequiredService<AuthHeaderHandler>();
    var httpClient = new HttpClient(authHandler)
    {
        BaseAddress = new Uri(builder.Configuration["BaseUrl"])
    };
    return httpClient;
});

// 3. 注册自动生成的CustomApi,注入配置好的HttpClient
builder.Services.AddScoped<CustomApi>(sp =>
{
    var httpClient = sp.GetRequiredService<HttpClient>();
    // 根据自动生成的构造函数调整:如果构造函数是(string baseUrl, HttpClient client),则传入BaseUrl
    return new CustomApi(builder.Configuration["BaseUrl"], httpClient);
    // 如果构造函数只接受HttpClient,直接传:return new CustomApi(httpClient);
});

// 如果用Blazored.LocalStorage,需要先注册
// builder.Services.AddBlazoredLocalStorage();

// 注册你的自定义AuthenticationStateProvider
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
builder.Services.AddAuthorizationCore();

await builder.Build().RunAsync();

关键说明

  1. 为什么用DelegatingHandler?
    自动生成的OpenAPI客户端会直接使用注入的HttpClient,通过Handler拦截请求,无需修改生成的代码,就能统一处理所有请求的认证头。
  2. Scoped生命周期的作用
    Blazor WASM中Scoped服务对应每个浏览器标签页实例,每次请求都会通过Handler获取最新的认证状态,避免使用过期令牌。
  3. 避免在Program.cs直接访问LocalStorage
    Program.cs是应用启动阶段执行的代码,此时还未进入浏览器环境,无法直接调用LocalStorage API,必须通过Scoped服务(如Handler)在运行时动态获取。

内容的提问来源于stack exchange,提问作者seho

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 04:35:22