C#中RSA公私钥生成JWT签名验证失败求助
RSA签名JWT在JWT.IO验证失败的解决方法
你用C#生成RSA签名的JWT后,用公钥在JWT.IO验证时显示签名无效,核心问题是你生成PEM格式公钥的方式错误——直接把XML格式的公钥转Base64并添加PEM头尾,得到的不是JWT.IO可识别的标准PEM密钥格式。
问题根源
RSACryptoServiceProvider.ToXmlString(false)生成的是XML结构的公钥,而JWT.IO需要的是PKCS#1或PKCS#8标准格式的PEM公钥。直接对XML字符串做Base64编码,本质是把XML文本转成了Base64,并非真正的密钥原始字节编码,自然无法通过签名验证。
修复方案
1. 正确生成标准PEM格式密钥
从RSA对象中直接导出密钥的原始字节(而非XML字符串),再转换成符合规范的PEM格式:
using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; class JwtRsaDemo { static void Main() { // 指定密钥长度,推荐2048位及以上 using (RSA rsa = RSA.Create(2048)) { // 导出私钥为PKCS#8格式字节,转换为标准PEM byte[] privateKeyBytes = rsa.ExportPkcs8PrivateKey(); string privateKeyPem = ConvertToPem(privateKeyBytes, "PRIVATE KEY"); // 导出公钥为SubjectPublicKeyInfo格式字节,转换为标准PEM byte[] publicKeyBytes = rsa.ExportSubjectPublicKeyInfo(); string publicKeyPem = ConvertToPem(publicKeyBytes, "PUBLIC KEY"); // 生成JWT var signingKey = new RsaSecurityKey(rsa); var credentials = new SigningCredentials(signingKey, SecurityAlgorithms.RsaSha256); var jwtToken = new JwtSecurityToken( issuer: "iss", audience: "aud", claims: new List<Claim> { new Claim("user_id", "123") }, expires: DateTime.UtcNow.AddMinutes(30), // 用UtcNow避免时区差异导致的验证问题 signingCredentials: credentials ); string token = new JwtSecurityTokenHandler().WriteToken(jwtToken); Console.WriteLine("生成的Token:"); Console.WriteLine(token); Console.WriteLine("\n公钥PEM:"); Console.WriteLine(publicKeyPem); } } // 辅助方法:将密钥字节转换为带换行的标准PEM格式 static string ConvertToPem(byte[] keyBytes, string keyType) { string base64 = Convert.ToBase64String(keyBytes, Base64FormattingOptions.InsertLineBreaks); return $"-----BEGIN {keyType}-----\n{base64}\n-----END {keyType}-----"; } }
2. 验证步骤
- 把代码生成的
publicKeyPem完整复制到JWT.IO的「Public Key」输入框(包含头尾的-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----) - 确认JWT.IO的「Algorithm」选择
RS256(与代码中SecurityAlgorithms.RsaSha256对应) - 避免使用
DateTime.Now生成过期时间,改用DateTime.UtcNow防止时区问题导致的验证失败
额外提示
- .NET Core/.NET 5+中推荐用
RSA.Create()替代RSACryptoServiceProvider,API更符合现代规范 - 密钥长度不要低于2048位,1024位已被认为不安全
内容的提问来源于stack exchange,提问作者Vijeesha Dream
相关产品推荐
相关产品推荐

