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

ASP.NET应用中使用OpenSSL RSA密钥实现JWT签名遇阻求助

问题:如何使用OpenSSL生成的RSA密钥正确创建JWT令牌?

生成密钥的OpenSSL命令

openssl genrsa -out keypair-2023.pem 4096
openssl rsa -in keypair-2023.pem -pubout -out pub-2023.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair-2023.pem -out priv-2023-v8.key

密钥文件格式

-----BEGIN PUBLIC KEY-----
{{ public key contents }}
-----END PUBLIC KEY-----

-----BEGIN PRIVATE KEY-----
{{ private key contents }}
-----END PRIVATE KEY-----

尝试的代码及错误

代码片段1

var rsaKey = RSA.Create();

rsaKey.ImportFromPem(privateKeyStr);
rsaKey.ImportFromPem(publicKeyStr);

var rsaParams = rsaKey.ExportParameters(true);

var securityKey = new RsaSecurityKey(rsaParams);

错误:System.Security.Cryptography.CryptographicException: 'Key does not exist.'(发生在ExportParameters行)

代码片段2

var privateKeyBuffer = new Span<byte>(new byte[privateKeyStr.Length]);
Convert.TryFromBase64String(privateKeyStr, privateKeyBuffer, out _);

var rsaKey = RSA.Create();
rsaKey.ImportRSAPrivateKey(privateKeyBuffer, out _);
rsaKey.ImportFromPem(publicKeyStr);

var rsaParams = rsaKey.ExportParameters(true);

错误:AsnContentException: The provided data is tagged with 'Universal' class value '0', but it should have been 'Universal' class value '16'(发生在ImportRSAPrivateKey行)

将ImportRSAPrivateKey替换为ImportPkcs8PrivateKey会抛出相同异常。

代码片段3(用于JWT签名)

var rsaKey = RSA.Create();

rsaKey.ImportFromPem(privateKeyStr);
rsaKey.ImportFromPem(publicKeyStr);

var securityKey = new RsaSecurityKey(rsaKey);
_signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha512);
_securityTokenHandler = new JwtSecurityTokenHandler();

错误:应用可启动,但创建JWT令牌时抛出System.Security.Cryptography.CryptographicException: 'Key does not exist.'


解决方案

核心问题分析

  1. 重复导入密钥覆盖私钥:同一个RSA实例先导入私钥再导入公钥,会覆盖私钥信息,导致后续需要私钥的操作(如ExportParameters(true)、JWT签名)失败。
  2. 错误处理PEM字符串:直接将包含PEM头/尾的完整字符串转换为Base64是错误的,ImportRSAPrivateKey/ImportPkcs8PrivateKey需要的是去除格式后的原始ASN.1字节,而ImportFromPem可以直接处理完整的PEM格式字符串。

正确实现代码

1. 创建JWT签名凭证(使用私钥)

// 确保privateKeyStr包含完整的PEM格式(包括-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----)
using var rsaKey = RSA.Create();
rsaKey.ImportFromPem(privateKeyStr);

// 私钥已包含公钥信息,无需单独导入公钥
var securityKey = new RsaSecurityKey(rsaKey);
_signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha512);
_securityTokenHandler = new JwtSecurityTokenHandler();

2. 使用公钥验证JWT令牌

// 确保publicKeyStr包含完整的PEM格式
using var rsaPublicKey = RSA.Create();
rsaPublicKey.ImportFromPem(publicKeyStr);

var validationParams = new TokenValidationParameters
{
    ValidateIssuer = true,
    ValidateAudience = true,
    ValidIssuer = "你的发行方标识",
    ValidAudience = "你的受众标识",
    IssuerSigningKey = new RsaSecurityKey(rsaPublicKey)
};

// 执行验证
_securityTokenHandler.ValidateToken(jwtToken, validationParams, out var validatedToken);

关键注意事项

  • 私钥文件是PKCS#8格式(-----BEGIN PRIVATE KEY-----),ImportFromPem可以直接识别并加载,无需额外转换。
  • 签名操作只需要私钥,公钥仅用于验证,不需要在签名时导入。
  • 始终使用using语句管理RSA实例,确保资源正确释放。

内容的提问来源于stack exchange,提问作者Trec Apps

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 01:02:47