Blazor WASM配置Negotiate+JWT双认证实现API访问保护
方案说明
你的设计思路完全可行:Windows认证仅用于初始访问时核验域用户身份,JWT只作为后续API访问的合法凭证,不需要承担用户身份认证的核心职能,这套逻辑非常适配企业内部域环境+Blazor WASM的部署场景。
之前配置失效的核心原因
你两次调用builder.Services.AddAuthentication()的写法是错误的:第二次调用会直接覆盖第一次注册的Negotiate(Windows认证)默认方案配置,最终只会保留最后一次注册的JwtBearer默认方案,导致两套认证逻辑都无法正常工作。ASP.NET Core不需要重复调用AddAuthentication,原生支持在一次认证注册中挂载多个认证方案。
具体实现步骤
不需要编写自定义中间件,用框架自带的多认证方案+授权策略就能实现全部需求。
1. 正确注册多认证方案
仅调用一次AddAuthentication,同时注册Windows认证和JWT认证两个方案:
using Microsoft.AspNetCore.Authentication.Negotiate; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; builder.Services.AddAuthentication(options => { // 初始获取Token的接口默认走Windows认证 options.DefaultScheme = NegotiateDefaults.AuthenticationScheme; }) .AddNegotiate() .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateAudience = true, ValidAudience = "xxx", ValidateIssuer = true, ValidIssuer = "xxx", ValidateLifetime = true, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWTSettings:Secret"]!)) }; });
2. 配置分层授权规则
全局配置授权策略,实现接口权限隔离:
builder.Services.AddAuthorization(options => { // 默认全局策略:所有接口默认要求JWT认证,直接拦截无JWT的域用户直连请求 options.DefaultPolicy = new AuthorizationPolicyBuilder() .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build(); // 单独策略:仅用于发放JWT的GetUser接口,走Windows认证 options.AddPolicy("WindowsAuthOnly", policy => { policy.AddAuthenticationSchemes(NegotiateDefaults.AuthenticationScheme) .RequireAuthenticatedUser(); }); }); // 注册中间件 app.UseAuthentication(); app.UseAuthorization();
给发放JWT的接口标记单独的授权策略:
[HttpGet] [Route("GetUser")] [Authorize(Policy = "WindowsAuthOnly")] public UserModel GetUser() { string? login = httpContextAccessor!.HttpContext!.User?.Identity?.Name?.Replace("domain\\", ""); return new UserModel{ UserName=login , JWT = CreateJWT(login)}; }
3. 开发环境放行Swagger
仅在开发环境跳过Swagger相关路径的授权校验,生产环境默认关闭:
if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); // 放行Swagger所有相关端点 app.MapWhen(context => context.Request.Path.StartsWithSegments("/swagger"), appBuilder => { appBuilder.Run(async context => await context.Response.NextAsync()); }); }
4. Blazor WASM端适配
应用首次加载时先调用/GetUser接口,浏览器会自动携带Windows认证凭证,拿到返回的JWT后存储到本地,后续所有API请求都在请求头中携带Authorization: Bearer {JWT字符串}即可。
安全加固建议
- JWT中增加专属应用标识声明,比如
new Claim("ClientType", "InternalBlazorApp"),Token校验时强制验证该声明,进一步拦截非授权客户端的请求 - JWT过期时间建议设置为15-30分钟,搭配静默刷新逻辑平衡安全性和使用体验
- 生产环境必须移除Swagger放行规则,避免接口详情泄露
内容的提问来源于stack exchange,提问作者Dorian
相关产品推荐
相关产品推荐

