.NET 6 System.IdentityModel.Tokens.Jwt 6.24.0与6.34.0行为差异问询
问题分析与解决方案
核心原因:密钥验证逻辑的默认规则收紧
升级到6.34.0及后续无漏洞版本后出现signature key was not found错误,核心是微软为修复漏洞,调整了JWT密钥验证的默认行为,主要变化包括:
- 算法匹配更严格:早期版本可能允许跨算法尝试密钥匹配,新版本要求验证密钥必须与JWT头部
alg字段声明的算法完全一致,不允许模糊匹配。 - 密钥格式校验更严谨:对对称密钥长度、非对称密钥格式(如RSA公钥的PEM/XML格式)的校验更严格,不符合要求的密钥直接被拒绝加载。
- JWKS处理逻辑优化:如果依赖JWKS端点获取密钥,新版本对密钥缓存、kid(密钥ID)匹配的逻辑做了调整,早期版本能匹配的密钥可能因kid不匹配或缓存未更新被过滤。
排查修复步骤
1. 确认JWT头部与密钥的算法匹配
直接解码JWT头部(用JwtSecurityTokenHandler.ReadJwtToken(token)获取头部信息),查看alg字段值(比如HS256、RS256),然后对应检查密钥:
- 若为HS系列算法:确保密钥长度符合要求(HS256至少32字节),新版本不再自动补全或转换短密钥。
- 若为RS系列算法:确认公钥是标准的PEM或XML格式,无效格式的密钥会被直接丢弃。
2. 检查AddJwtBearer的密钥配置
对比旧版本配置,重点确认以下几点:
- 明确指定
TokenValidationParameters中的ValidAlgorithms和IssuerSigningKeys,不要依赖默认值:services.AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidAlgorithms = new[] { SecurityAlgorithms.HmacSha256 }, // 硬编码匹配JWT的alg IssuerSigningKeys = new List<SecurityKey> { new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-32-byte-secret-key")) } }; }); - 若用JWKS,确认
MetadataAddress正确,必要时禁用缓存测试是否是缓存问题:services.AddJwtBearer(options => { options.MetadataAddress = "https://your-issuer/.well-known/openid-configuration"; // 临时禁用缓存排查 options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>( options.MetadataAddress, new OpenIdConnectConfigurationRetriever(), new HttpDocumentRetriever { RequireHttps = true }); });
3. 验证密钥ID(kid)匹配
如果JWT头部带有kid字段,必须确保你的验证密钥集合中存在对应kid的密钥。新版本严格要求kid匹配,早期版本可能忽略kid直接用第一个算法匹配的密钥。
4. 开启详细日志定位问题
在AddJwtBearer中添加事件日志,输出具体错误细节:
services.AddJwtBearer(options => { options.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { Console.WriteLine($"Auth failed: {context.Exception.Message}"); if (context.Exception.InnerException != null) { Console.WriteLine($"Inner error: {context.Exception.InnerException.Message}"); } return Task.CompletedTask; } }; });
总结
这不是兼容性bug,是新版本为修复漏洞而收紧了验证规则导致的。只要确保算法匹配、密钥格式正确、kid一致,就能解决问题。
内容的提问来源于stack exchange,提问作者VZajac
相关产品推荐
相关产品推荐

