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

如何在C#中实现带keyId的JWS头及第三方URL的RS256签名验证

C#中实现RS256签名验证方案(对应Java Nimbus库流程)

问题背景

第三方网站跳转至我方域名时,通过RSA私钥+RS256算法对跳转URL签名,签名存入URL的signature参数,同时携带keyId参数。我方已从URL参数生成JwtPayload,但需要复现Java Nimbus库的以下步骤:

  1. 生成包含RS256算法和keyId的JWS Header
  2. 构造待验证的签名输入并使用公钥验证签名

实现方案(基于jose-jwt库)

1. 安装依赖

通过NuGet安装jose-jwt库,用于JWT相关的编码和签名验证操作。

2. 构造并编码JWS Header

对应Java中JWSHeader.Builder(JWSAlgorithm.RS256).keyID(keyId).build()的逻辑:

// 从URL参数中获取第三方传入的keyId
string keyId = "MvJikN0EgR5vNplYFZR50z2G******"; // 示例值

// 构造JWS Header,指定算法为RS256并设置keyId
var jwsHeader = new Jose.JwtHeader
{
    { "alg", Jose.JwsAlgorithm.RS256 },
    { "kid", keyId }
};

// 将Header序列化为JSON并做Base64Url编码
string encodedHeader = Jose.Base64Url.Encode(Newtonsoft.Json.JsonConvert.SerializeObject(jwsHeader));

3. 编码已生成的JwtPayload

将已构造的JwtPayload序列化为JSON并做Base64Url编码,对应Java中signedJWT.getSigningInput()的前半部分:

// 你已生成的JwtPayload
var claims = new[]
{
    new Claim("partnerUrl", "https://www.my-domain.com"),
    new Claim("dealId", "testDealId"),
    new Claim("expireOn", "2023-02-18T00:00:00.000Z"),
};
var payload = new JwtPayload(claims);

// 序列化Payload并做Base64Url编码
string encodedPayload = Jose.Base64Url.Encode(Newtonsoft.Json.JsonConvert.SerializeObject(payload));

4. 处理URL中的签名参数

从URL中提取signature参数,先解码URL编码(比如%3D对应=),再转换为字节数组:

// 从URL参数中获取signature(注意先解码URL编码)
string urlEncodedSignature = "VGhpcyBpcyBhIHNpZ25hdHVyZSB0byB2ZXJ5IHRoaXMgaW5zdGFuY2U%3D"; // 示例值
string decodedSignature = System.Web.HttpUtility.UrlDecode(urlEncodedSignature);
byte[] signatureBytes = Jose.Base64Url.Decode(decodedSignature);

5. 使用公钥验证签名

对应Java中RSASSAVerifier的验证逻辑,先加载公钥,再验证签名输入的完整性:

// 加载第三方提供的RSA公钥(示例为PEM格式)
string publicKeyPem = "-----BEGIN PUBLIC KEY-----..." + 
                      "-----END PUBLIC KEY-----";
RSA rsa = RSA.Create();
rsa.ImportFromPem(publicKeyPem.ToCharArray());

// 构造签名输入:编码后的Header + "." + 编码后的Payload
string signingInput = $"{encodedHeader}.{encodedPayload}";
byte[] signingInputBytes = System.Text.Encoding.UTF8.GetBytes(signingInput);

// 验证签名:使用SHA256哈希算法+PKCS1填充,对应RS256标准
bool isValid = rsa.VerifyData(
    signingInputBytes,
    signatureBytes,
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1
);

简化验证方式(直接构造JWT字符串验证)

也可以将Header、Payload、Signature组合成标准JWT格式,用jose-jwt的Decode方法一键验证:

string jwt = $"{encodedHeader}.{encodedPayload}.{decodedSignature}";
bool isValid = false;
try
{
    // 解码并验证签名,验证失败会抛出InvalidSignatureException
    string decodedPayload = Jose.JWT.Decode(jwt, rsa, Jose.JwsAlgorithm.RS256);
    isValid = true;
}
catch (Jose.InvalidSignatureException)
{
    isValid = false;
}

注意事项

  • 序列化一致性:确保Header和Payload的JSON序列化格式与Java端一致(比如字段顺序、日期格式),建议使用Newtonsoft.Json保持兼容性。
  • 公钥格式:如果第三方提供的是XML格式公钥,使用rsa.ImportFromXmlString(publicKeyXml)替代ImportFromPem。
  • URL解码:必须对signature和keyId参数做URL解码,否则会导致Base64Url解码失败。

内容的提问来源于stack exchange,提问作者Fazla Elahi Md Jubayer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:53:17