ASP.NET Core WebAPI如何实现可选JWT Bearer Token?
ASP.NET Core 可选JWT Bearer Token原生实现方案
ASP.NET Core 原生支持同一个接口可选择携带/不携带JWT访问的场景,不需要手动解析Token,推荐以下两种实现方案:
方案1:全局适配(适合多数接口都需要可选JWT的场景)
首先在Program.cs中配置JWT认证服务,核心是跳过默认的401挑战逻辑,让未携带Token的请求也能正常进入接口:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 常规JWT校验配置,按需调整 options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) }; // 核心配置:跳过401挑战,不拦截未携带Token的请求 options.Events = new JwtBearerEvents { OnChallenge = context => { context.HandleResponse(); return Task.CompletedTask; } }; }); // 注册授权服务 builder.Services.AddAuthorization(); // 中间件注册顺序不能错 app.UseAuthentication(); app.UseAuthorization();
在接口中直接通过HttpContext.User判断认证状态即可:
[HttpGet("common/data")] public IActionResult GetPublicOrPrivateData() { // 已携带有效JWT的逻辑 if (HttpContext.User.Identity?.IsAuthenticated == true) { var userId = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; var userRole = HttpContext.User.FindFirst(ClaimTypes.Role)?.Value; return Ok(new { Type = "私有内容", UserId = userId, Role = userRole }); } // 未携带JWT的逻辑 return Ok(new { Type = "公开内容", Data = "未登录用户可见内容" }); }
方案2:策略适配(推荐,仅部分接口需要可选JWT的场景)
如果仅少量接口需要可选JWT,其他接口仍需要强制认证,推荐使用自定义授权策略实现,不会影响全局认证逻辑:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 常规JWT校验配置,和上面一致即可 options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) }; }); // 自定义可选JWT的授权策略 builder.Services.AddAuthorization(options => { options.AddPolicy("OptionalJwt", policy => { policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme); // 不要求必须认证通过,只要走完认证流程即可 policy.RequireAssertion(_ => true); }); }); // 中间件注册和上面一致 app.UseAuthentication(); app.UseAuthorization();
需要可选JWT的接口单独标注策略即可,其他需要强制登录的接口仍使用默认[Authorize]特性:
[HttpGet("optional/data")] [Authorize(Policy = "OptionalJwt")] public IActionResult GetOptionalData() { // 逻辑和方案1完全一致,通过HttpContext.User判断状态 if (HttpContext.User.Identity?.IsAuthenticated == true) { var userId = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; return Ok(new { IsLogin = true, UserId = userId }); } return Ok(new { IsLogin = false, Data = "公开内容" }); }
两种方案都自动完成了JWT的签名校验、过期校验、格式校验,比手动解析Token的安全性和可维护性更高,也完全兼容ASP.NET Core的身份认证体系。
内容的提问来源于stack exchange,提问作者DoubleVoid
相关产品推荐
相关产品推荐

