ASP.NET Core 6校验Spring Security生成JWT的认证方案
ASP.NET Core Web API 6 适配Spring Security HS256 JWT 跨栈认证互通方案
以下方案可直接落地部署,无需修改现有Spring Boot 2.7.0服务的任何代码,所有校验逻辑100%对齐现有Spring Security侧的JWT生成、校验规则。
前置依赖安装
- 通过NuGet安装与.NET 6 LTS版本匹配的认证组件:
Microsoft.AspNetCore.Authentication.JwtBearer(版本选择6.0.x系列,避免高版本兼容性问题)。
配置参数对齐
所有参数必须和Java侧JwtConstants配置完全一致,在appsettings.json中添加JWT配置节点:
"JwtSettings": { "SigningKey": "填入与Java侧JwtConstants.SIGNING_KEY完全相同的字符串", "ValidIssuer": "system", "ClockSkew": 0 }
注意:.NET侧密钥编码必须和Java侧保持一致,统一使用UTF8编码将密钥字符串转为字节数组,完全对齐Java侧
new MACSigner(SIGNING_KEY.getBytes(StandardCharsets.UTF_8))的签名逻辑,避免签名校验失败。设置ClockSkew=0是为了关闭.NET默认的5分钟过期时间宽容,和Java侧过期判断逻辑完全对齐。
中间件注册(Program.cs)
直接替换Program.cs中对应部分的代码,所有逻辑已对齐Spring侧JwtAuthenticationFilter的校验流程:
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; var builder = WebApplication.CreateBuilder(args); var jwtConfig = builder.Configuration.GetSection("JwtSettings"); var signingKeyBytes = Encoding.UTF8.GetBytes(jwtConfig["SigningKey"]!); // 注册JWT认证服务 builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { // 签名校验:对齐HS256算法+统一密钥规则 ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(signingKeyBytes), ValidAlgorithms = new[] { SecurityAlgorithms.HmacSha256 }, // 签发方校验:对齐Java侧固定iss=system的规则 ValidateIssuer = true, ValidIssuer = jwtConfig["ValidIssuer"], // 关闭固定受众校验,后续自定义逻辑对齐Java侧租户有效性判断 ValidateAudience = false, // 生命周期校验:对齐Java侧令牌过期判断规则 ValidateLifetime = true, ClockSkew = TimeSpan.FromSeconds(int.Parse(jwtConfig["ClockSkew"]!)), // 关闭.NET默认的声明名重映射,保证声明Key和Java侧完全一致 NameClaimType = JwtRegisteredClaimNames.Sub, RoleClaimType = "scopes" }; // 令牌校验通过后的扩展逻辑:对齐Java侧的租户有效性校验 options.Events = new JwtBearerEvents { OnTokenValidated = async context => { // 提取aud对应当前租户ID var tenantId = context.Principal?.FindFirst(JwtRegisteredClaimNames.Aud)?.Value; if (string.IsNullOrWhiteSpace(tenantId)) { context.Fail("令牌缺少合法租户标识"); return; } // 如需接入租户服务校验,可通过DI获取服务实例: // var tenantService = context.HttpContext.RequestServices.GetRequiredService<ITenantService>(); // var isValid = await tenantService.CheckTenantStatusAsync(tenantId); var isValid = !string.IsNullOrWhiteSpace(tenantId); // 替换为实际租户校验逻辑 if (!isValid) { context.Fail("当前租户状态无效,拒绝访问"); } } }; }); // 注册授权服务,对齐Java侧权限校验规则 builder.Services.AddAuthorization(options => { // 示例:对齐Java侧ROLE_ADMIN权限的访问策略 options.AddPolicy("AdminOnly", policy => policy.RequireRole("ROLE_ADMIN")); }); builder.Services.AddControllers(); var app = builder.Build(); // 注意中间件顺序:Authentication必须在Authorization之前注册 app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
说明:JwtBearer组件默认就支持从
Authorization请求头提取Bearer <token>格式的令牌,和Spring侧过滤器的提取逻辑完全一致,无需额外开发令牌提取代码。
业务接口使用方式
- 基础鉴权:在Controller或Action上标注
[Authorize]特性即可完成JWT合法性校验,效果等同于Spring侧的接口鉴权注解。 - 权限控制:通过策略或角色校验控制接口访问权限,示例:
[ApiController] [Route("api/invoice")] [Authorize] public class InvoiceController : ControllerBase { /// <summary> /// PDF发票生成接口,仅ROLE_ADMIN权限可访问 /// </summary> [HttpPost("generate")] [Authorize(Policy = "AdminOnly")] public async Task<IActionResult> GenerateInvoice([FromBody] InvoiceRequest req) { // 获取当前登录用户名(对应JWT的sub声明) var currentUser = User.Identity?.Name; // 获取当前租户ID(对应JWT的aud声明) var tenantId = User.FindFirst(JwtRegisteredClaimNames.Aud)?.Value; // 获取当前用户所有权限(对应JWT的scopes声明,多权限自动拆分为同Key多Claim) var permissions = User.FindAll("scopes").Select(c => c.Value).ToList(); // 此处写入PDF生成业务逻辑 return Ok(new { CurrentUser = currentUser, TenantId = tenantId }); } }
常见踩坑说明
- 不要随意修改密钥编码格式,必须使用UTF8编码转字节数组,否则会出现签名校验失败的问题。
- 必须显式配置
NameClaimType和RoleClaimType,否则User.Identity.Name无法正确获取用户名,角色权限校验也会失效。 - 如果Java侧的
aud、scopes声明是数组类型,.NET会自动将数组元素拆分为多个同名Claim,直接调用FindAll(声明Key)即可获取全量值,无需额外做JSON反序列化。 - 客户端调用时直接沿用原有Spring服务的请求头格式,携带
Authorization: Bearer <原有JWT令牌>即可访问.NET服务,不需要做任何额外适配。
内容的提问来源于stack exchange,提问作者Đỗ Như Vỹ
相关产品推荐
相关产品推荐

