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

.NET Framework 4.5下使用预生成ES512私钥签名JWT遇阻

解决方案:.NET Framework 4.5 VB.NET 用ES512 PEM私钥生成JWT Bearer令牌

一、JWT必填字段取值说明

iss(签发者)与aud(受众)

  • iss:填写你方在支付API平台的商户ID/专属账号ID,用于标识令牌的签发主体,让API知道请求来自哪个合法商户。
  • aud:填写支付API的官方域名或指定受众标识(例如https://api.your-payment-provider.com),限定令牌的使用范围,防止被其他服务滥用。

其他必填字段

  • iat:当前时间的Unix时间戳(令牌签发时间)
  • exp:令牌过期时间的Unix时间戳(建议设为签发后15-30分钟,避免过长导致泄露风险)
  • kid:API提供商给你的Key ID,用于关联你使用的私钥
  • jti:随机唯一字符串(如GUID转无分隔符字符串),防止令牌重复提交

二、核心实现:加载PEM私钥并生成JWT

.NET Framework 4.5无原生PEM解析方法,需结合BouncyCastle(解析PEM密钥)和Jose-JWT(生成JWT)实现,步骤如下:

1. 安装NuGet包

  • 安装BouncyCastle
  • 安装Jose-JWT

2. VB.NET代码实现

解析PEM私钥为BouncyCastle密钥对象

Imports Org.BouncyCastle.Crypto
Imports Org.BouncyCastle.Crypto.Parameters
Imports Org.BouncyCastle.OpenSsl
Imports Org.BouncyCastle.Security
Imports Jose
Imports System.Text

Private Function ParseEcPrivateKeyFromPem(pemKey As String) As ECPrivateKeyParameters
    Using reader As New StringReader(pemKey)
        Dim pemReader As New PemReader(reader)
        Dim keyObj As Object = pemReader.ReadObject()
        Return DirectCast(keyObj, ECPrivateKeyParameters)
    End Using
End Function

转换密钥为Jose-JWT兼容格式

Jose-JWT需要ES512对应的x(公钥X坐标)、y(公钥Y坐标)、d(私钥参数),从BouncyCastle密钥中提取并转成JWT要求的Base64Url编码:

Private Function ConvertToJoseEcKey(ecKey As ECPrivateKeyParameters) As Dictionary(Of String, Object)
    Dim ecParams As ECDomainParameters = ecKey.Parameters
    Dim publicKey As ECPublicKeyParameters = New ECPublicKeyParameters(ecParams.G.Multiply(ecKey.D), ecParams)
    
    Dim xBytes As Byte() = publicKey.Q.AffineXCoord.GetEncoded()
    Dim yBytes As Byte() = publicKey.Q.AffineYCoord.GetEncoded()
    Dim dBytes As Byte() = ecKey.D.ToByteArrayUnsigned()
    
    Return New Dictionary(Of String, Object) From {
        {"kty", "EC"},
        {"crv", "P-521"}, ' ES512对应P-521椭圆曲线
        {"x", Base64Url.Encode(xBytes)},
        {"y", Base64Url.Encode(yBytes)},
        {"d", Base64Url.Encode(dBytes)}
    }
End Function

生成JWT令牌

Private Function GenerateEs512Jwt(pemPrivateKey As String, kid As String, iss As String, aud As String) As String
    ' 解析私钥
    Dim ecPrivateKey = ParseEcPrivateKeyFromPem(pemPrivateKey)
    ' 转换为Jose-JWT可用格式
    Dim joseKey = ConvertToJoseEcKey(ecPrivateKey)
    
    ' 构建JWT头部
    Dim header = New Dictionary(Of String, Object) From {
        {"alg", "ES512"},
        {"kid", kid}
    }
    
    ' 构建JWT声明
    Dim claims = New Dictionary(Of String, Object) From {
        {"iss", iss},
        {"aud", aud},
        {"iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds()},
        {"exp", DateTimeOffset.UtcNow.AddMinutes(20).ToUnixTimeSeconds()},
        {"jti", Guid.NewGuid().ToString("N")}
    }
    
    ' 生成并返回JWT
    Return Jose.JWT.Encode(claims, joseKey, JwsAlgorithm.ES512, header)
End Function

3. 调用示例

' 替换为你的实际参数
Dim pemKey As String = "-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----"
Dim keyId As String = "你的Key ID"
Dim issuer As String = "你的商户ID"
Dim audience As String = "支付API的域名"

Dim jwtToken As String = GenerateEs512Jwt(pemKey, keyId, issuer, audience)
' 添加到请求头
rest_request.AddHeader("Authorization", "Bearer " + jwtToken)

三、常见问题排查

  1. jwt.io标记令牌无效:
    • 检查头部alg是否为ES512,kid是否与API提供的一致
    • 确认iss、aud完全匹配API要求(包括大小写和格式)
    • 若API提供公钥,可在jwt.io的「Verify Signature」栏粘贴公钥验证签名
  2. API返回401 Unauthorized:
    • 检查exp是否未过期、iat是否为当前有效时间
    • 确认iss和aud无拼写错误,多数API对这两个字段校验严格
    • 检查PEM私钥字符串是否完整(包含首尾的-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----行)
  3. 代码崩溃:
    • 确保BouncyCastle与Jose-JWT版本兼容,建议使用稳定版
    • 确认私钥确实是ES512(P-521曲线),而非其他EC曲线(如P-256)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 13:26:05