Blazor WASM中HTTP Client自动附加身份Cookie或API验证AccessToken的方案
我来帮你搞定这个问题!你现在遇到的是Blazor WASM调用自己作为Identity Provider的API时,API只认身份Cookie不认Access Token的情况,或者想让WASM自动把Cookie带上。下面给你两种可行的解决方案:
方案一:配置Http Handler让Blazor WASM自动携带Cookie
Blazor WASM默认用AuthorizationMessageHandler添加Access Token,但不会自动带上浏览器里的身份Cookie。要让请求自动附加Cookie,你可以自定义一个HttpMessageHandler来开启浏览器请求的凭证包含选项:
步骤1:创建自定义Cookie Handler
在Blazor WASM项目中添加一个新类:
public class CookieIncludingHandler : DelegatingHandler { protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { // 告诉浏览器发送请求时包含当前域名下的Cookie request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include); return await base.SendAsync(request, cancellationToken); } }
步骤2:注册Handler并配置HttpClient
修改Blazor项目的Program.cs,注册自定义Handler并添加到你的授权HttpClient中:
public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("app"); // 注册自定义Cookie Handler builder.Services.AddScoped<CookieIncludingHandler>(); builder.Services.AddOidcAuthentication(options => { builder.Configuration.Bind("oidc", options.ProviderOptions); options.UserOptions.RoleClaim = "role"; }).AddAccountClaimsPrincipalFactory<CustomUserFactory>(); // 配置授权HttpClient,同时添加Cookie Handler和Authorization Handler builder.Services.AddHttpClient<IAuthorizedRestService, AuthorizedRestService>( client => client.BaseAddress = new Uri("https://localhost:5002/api/mart/v1/")) .AddHttpMessageHandler<CookieIncludingHandler>() // 先添加Cookie Handler .AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>() .ConfigureHandler(authorizedUrls: new[] { "https://localhost:5002" })); builder.Services.AddHttpClient("noauth", option => option.BaseAddress = new Uri("https://localhost:5002/api/mart/v1/")); builder.Services.AddScoped<IRestService, RestService>(); await builder.Build().RunAsync(); }
这样配置后,每个通过IAuthorizedRestService发送的请求都会自动带上浏览器中的Cookie,API就能正常验证身份了。
方案二:配置API验证Access Token而非身份Cookie
如果你更倾向于用无状态的Access Token验证(符合RESTful设计),可以修改API的认证配置,让它优先验证Bearer Token:
步骤1:设置默认认证Scheme
修改API项目Startup.cs中的AddAuthentication配置,将默认认证和挑战Scheme设置为IdentityServer的JWT Bearer Scheme:
services.AddAuthentication(options => { // 设置默认用JWT Bearer验证 options.DefaultAuthenticateScheme = IdentityServerJwtConstants.IdentityServerJwtBearerScheme; options.DefaultChallengeScheme = IdentityServerJwtConstants.IdentityServerJwtBearerScheme; }) .AddGoogle("Google", options => { options.ClientId = configuration["ExternalLoginApiKey:GoogleClientId"]; options.ClientSecret = configuration["ExternalLoginApiKey:GoogleClientSecret"]; }) .AddFacebook("Facebook", options => { options.AppId = configuration["ExternalLoginApiKey:FacebookAppId"]; options.AppSecret = configuration["ExternalLoginApiKey:FacebookAppSecret"]; }) .AddIdentityServerJwt();
步骤2:确保Client配置包含API范围
检查你的Client配置,确保AllowedScopes包含API的资源范围(默认情况下,AddApiAuthorization会创建一个名为{ApiProjectName}的API资源,比如如果你的API项目叫MartApi,范围就是MartApi):
option.Clients.Add(new Client { // 其他配置不变 AllowedScopes = { "openid", "profile", "email","id", "MartApi" }, // 添加API范围 // 其他配置不变 });
步骤3:验证控制器授权
确保API的控制器或Action上添加了[Authorize]属性,这样API会自动验证请求头中的Authorization: Bearer {token}:
[ApiController] [Route("api/mart/v1/[controller]")] [Authorize] public class ProductsController : ControllerBase { // 你的接口逻辑 }
这样配置后,API会优先验证请求头中的Bearer Token,而不是依赖Cookie,完美适配Blazor WASM的调用方式。
内容的提问来源于stack exchange,提问作者chima okoli

