使用System.IdentityModel.Tokens.Jwt验证RS256签名JWT遇签名无效错误
你遇到的以下签名验证错误,虽然JWT.io能正常通过,但在System.IdentityModel.Tokens.Jwt库中失败,同时还存在PII信息无法显示的问题,我来帮你逐一解决:
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException IDX10503: Signature validation failed. Keys tried: '[PII is hidden]'. Exceptions caught: '[PII is hidden]'. token: '[PII is hidden]'.
一、修复RS256签名验证失败问题
结合你的LinqPad代码,我发现几个关键调整点:
1. 简化密钥配置,直接设置签名密钥
你当前使用IssuerSigningKeyResolver解析密钥,但对于单证书场景,直接设置IssuerSigningKey更简单且不易出错。修改TokenValidationParameters的配置:
var p = new TokenValidationParameters { IssuerSigningKey = new X509SecurityKey(c), // 测试阶段可临时关闭 issuer/audience 验证(生产环境建议按需开启) ValidateIssuer = false, ValidateAudience = false };
2. 确认证书公钥加载正常
有时候X509证书加载后,公钥可能未正确提取。可以添加一行代码验证:
// 在LinqPad中用Dump查看公钥信息 c.PublicKey.Key.Dump("Loaded Public Key");
如果能正常输出公钥详情,说明证书加载没问题;如果报错,建议将证书编码从Encoding.ASCII改为Encoding.UTF8(PEM格式证书用UTF8更稳妥)。
3. 验证Token算法匹配
你的Token头eyJhbGciOiJSUzI1NiJ9解码后是{"alg":"RS256"},这部分是正确的,确保和你使用的签名算法一致即可。
二、取消PII隐藏,查看详细错误信息
在LinqPad中,通过app.config或machine.config设置enableLoggingKnownPii通常不生效,因为LinqPad的运行环境和普通.NET应用不同。你需要通过代码手动开启PII日志:
在代码开头添加以下配置:
// 开启PII日志,让错误信息显示具体内容 IdentityModelEventSource.ShowPII = true;
这样错误信息里的[PII is hidden]就会替换为实际的密钥、异常详情和Token内容,帮你精准定位问题。
如果是在普通.NET应用中,确保配置节正确设置:
<configuration> <appSettings> <add key="IdentityModelEventSource.ShowPII" value="true" /> </appSettings> <system.identityModel> <identityConfiguration> <securityTokenHandlers> <add type="System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler, System.IdentityModel.Tokens.Jwt"> <validationParameters> <add key="logKnownPII" value="true" /> </validationParameters> </add> </securityTokenHandlers> </identityConfiguration> </system.identityModel> </configuration>
整合后的测试代码
把上述修改整合到你的LinqPad代码中,即可同时解决验证问题和查看详细错误:
void Main() { // 开启PII日志,显示详细错误信息 IdentityModelEventSource.ShowPII = true; var cText = "-----BEGIN CERTIFICATE-----" + "MIIBljCCAUACCQCIDMpqK7WfWDANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJV" + "UzETMBEGA1UECAwKU29tZS1TdGF0ZTESMBAGA1UECgwJTHV4b3R0aWNhMRowGAYD" + "VQQLDBFMdXhvdHRpY2EgZXllY2FyZTAeFw0xODA1MjMxNTE1MjdaFw0yODA1MjAx" + "NTE1MjdaMFIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYD" + "VQQKDAlMdXhvdHRpY2ExGjAYBgNVBAsMEUx1eG90dGljYSBleWVjYXJlMFwwDQYJ" + "KoZIhvcNAQEBBQADSwAwSAJBAKuMYcirPj81WBtMituJJenF0CG/HYLcAUOtWKl1" + "HchC0dM8VRRBI/HV+nZcweXzpjhX8ySa9s7kJneP0cuJiU8CAwEAATANBgkqhkiG" + "9w0BAQsFAANBAKEM8wQwlqKgkfqnNFcbsZM0RUxS+eWR9LvycGuMN7aL9M6GOmfp" + "QmF4MH4uvkaiZenqCkhDkyi4Cy81tz453tQ=" + "-----END CERTIFICATE-----"; var c = new X509Certificate2(Encoding.UTF8.GetBytes(cText)); // 验证公钥是否加载成功 c.PublicKey.Key.Dump("Loaded Public Key"); var p = new TokenValidationParameters { IssuerSigningKey = new X509SecurityKey(c), ValidateIssuer = false, ValidateAudience = false }; var h = new JwtSecurityTokenHandler(); var token = @"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJuLmNoaWVmZm8iLCJleHAiOjE1MjcyMzg4ODEsImlzcyI6Imx1eCJ9.BAaYzLwokmdKqLi6zKjGIpDXd__dZxi5PUWWHS3PSLPDYAInzPbEK8o4WxunoGD7eA0qtQNaxNpzeOc3BHrd4w"; try { h.ValidateToken(token, p, out SecurityToken validatedToken); validatedToken.Dump("Validated Token"); "Token validated successfully!".Dump(); } catch (Exception ex) { ex.Dump("Validation Error Details"); } }
内容的提问来源于stack exchange,提问作者Carlo Bos

