You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 07:05:12