如何在.NET Framework 4.8中使用RSA公钥验证签名Token?
.NET Framework 4.8验证.NET Core 6生成的JWT解决方案
方案一:修改.NET Core端密钥生成格式(推荐)
.NET Framework 4.8的RSA原生支持XML格式密钥导入,因此在Core端生成密钥时额外导出XML格式公钥,即可直接在Framework端使用:
修改后的.NET Core密钥生成代码
using System.Security.Cryptography; public class KeyPairGenerator { public static void GenerateKeyPair(string directoryPath) { using RSA rsa = RSA.Create(); // 保留原PKCS8私钥供Core端使用 File.WriteAllText(Path.Join(directoryPath, "/private.key"), Convert.ToBase64String(rsa.ExportPkcs8PrivateKey())); // 导出XML格式公钥供Framework端使用 File.WriteAllText(Path.Join(directoryPath, "/public.xml"), rsa.ToXmlString(false)); } }
.NET Framework 4.8验证代码
using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using Microsoft.IdentityModel.Tokens; public class JwtValidator { public static ClaimsPrincipal ValidateToken(string token, string publicKeyXml) { RSA rsa = RSA.Create(); rsa.FromXmlString(publicKeyXml); RsaSecurityKey securityKey = new RsaSecurityKey(rsa); JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); TokenValidationParameters validationParameters = new TokenValidationParameters() { ValidateLifetime = true, ValidateAudience = true, ValidateIssuer = true, ValidIssuer = "test-service", ValidAudience = "test-service-client", IssuerSigningKey = securityKey }; return tokenHandler.ValidateToken(token, validationParameters, out _); } }
方案二:在.NET Framework 4.8中解析SubjectPublicKeyInfo格式公钥
若无法修改Core端密钥生成逻辑,可手动解析SPKI格式公钥,提取RSA模数和指数后导入:
SPKI解析工具类
using System; using System.IO; using System.Linq; using System.Security.Cryptography; public static class RsaSpkiParser { public static RSAParameters ParseSubjectPublicKeyInfo(byte[] spkiBytes) { using var ms = new MemoryStream(spkiBytes); using var reader = new BinaryReader(ms); // 跳过SPKI顶层SEQUENCE ReadAsn1Tag(reader, 0x30); // 跳过算法标识符SEQUENCE ReadAsn1Tag(reader, 0x30); // 跳过RSA加密OID ReadAsn1Tag(reader, 0x06); reader.ReadBytes(9); // 跳过NULL字段 ReadAsn1Tag(reader, 0x05); // 读取BIT STRING(包含RSA公钥) ReadAsn1Tag(reader, 0x03); reader.ReadByte(); // 跳过未使用位数标记 // 读取RSA公钥SEQUENCE ReadAsn1Tag(reader, 0x30); // 解析模数 ReadAsn1Tag(reader, 0x02); byte[] modulus = reader.ReadBytes(GetAsn1Length(reader)); if (modulus[0] == 0) modulus = modulus.Skip(1).ToArray(); // 解析指数 ReadAsn1Tag(reader, 0x02); byte[] exponent = reader.ReadBytes(GetAsn1Length(reader)); return new RSAParameters { Modulus = modulus, Exponent = exponent }; } private static void ReadAsn1Tag(BinaryReader reader, byte expectedTag) { byte tag = reader.ReadByte(); if (tag != expectedTag) throw new InvalidOperationException($"Expected ASN.1 tag 0x{expectedTag:X2}, got 0x{tag:X2}"); } private static int GetAsn1Length(BinaryReader reader) { byte lengthByte = reader.ReadByte(); if ((lengthByte & 0x80) == 0) return lengthByte; int lengthBytesCount = lengthByte & 0x7F; byte[] lengthBytes = reader.ReadBytes(lengthBytesCount); Array.Reverse(lengthBytes); return BitConverter.ToInt32(lengthBytes.Concat(new byte[4 - lengthBytesCount]).ToArray(), 0); } }
.NET Framework 4.8验证代码(使用解析器)
using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using Microsoft.IdentityModel.Tokens; public class JwtValidator { public static ClaimsPrincipal ValidateToken(string token, string publicKeyBase64) { byte[] spkiBytes = Convert.FromBase64String(publicKeyBase64); RSAParameters rsaParams = RsaSpkiParser.ParseSubjectPublicKeyInfo(spkiBytes); RSA rsa = RSA.Create(); rsa.ImportParameters(rsaParams); RsaSecurityKey securityKey = new RsaSecurityKey(rsa); JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); TokenValidationParameters validationParameters = new TokenValidationParameters() { ValidateLifetime = true, ValidateAudience = true, ValidateIssuer = true, ValidIssuer = "test-service", ValidAudience = "test-service-client", IssuerSigningKey = securityKey }; return tokenHandler.ValidateToken(token, validationParameters, out _); } }
内容的提问来源于stack exchange,提问作者El Goodo
相关产品推荐
相关产品推荐

