C#如何使用JSON格式私钥签名Header与Payload生成Client Assertion
ES512算法Client Assertion签名实现方案
核心错误排查
- 你使用的私钥为EC椭圆曲线类型,对应P-521曲线、ES512签名算法,原代码初始化
RSACryptoServiceProvider属于RSA算法类,与密钥类型完全不匹配 - 原签名逻辑不符合JWT规范:JWT签名对象是
header.payload拼接字符串的UTF8字节数组,签名结果直接做Base64Url编码即可,不需要额外转字符串后二次编码 - JWK格式的私钥需要先解析
d/x/y三个核心参数,不能直接读取整个JSON文件内容作为密钥输入
完整实现代码
首先先实现Base64Url编码解码辅助方法,符合JWT/JWK规范:
// Base64Url编码 public static string Base64UrlEncode(byte[] input) { return Convert.ToBase64String(input) .TrimEnd('=') .Replace('+', '-') .Replace('/', '_'); } // Base64Url解码 public static byte[] Base64UrlDecode(string input) { input = input.Replace('-', '+').Replace('_', '/'); switch (input.Length % 4) { case 2: input += "=="; break; case 3: input += "="; break; } return Convert.FromBase64String(input); }
然后修改你的GetSignedClientAssertion方法:
public string GetSignedClientAssertion() { // 1. 构造header和payload,生成待签名的拼接字符串 var header = new Dictionary<string, string>() { { "typ" , "JWT"}, { "alg", "ES512"}, { "kid", "TST_Staging" } }; var headerBytes = Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(header)); var payloadBytes = Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(GetClaims())); string unsignedToken = $"{Base64UrlEncode(headerBytes)}.{Base64UrlEncode(payloadBytes)}"; // 2. 加载JWK格式的EC私钥 var filename = System.Web.HttpContext.Current.Server.MapPath("Private.json"); string jwkContent = File.ReadAllText(filename); dynamic jwk = Newtonsoft.Json.JsonConvert.DeserializeObject(jwkContent); // 解析JWK参数,构造EC密钥参数 var ecParams = new ECParameters { Curve = ECCurve.NamedCurves.nistP521, // 对应crv=P-521 D = Base64UrlDecode(jwk.d.ToString()), Q = new ECPoint { X = Base64UrlDecode(jwk.x.ToString()), Y = Base64UrlDecode(jwk.y.ToString()) } }; // 3. 用EC私钥签名 using (var ecdsa = ECDsa.Create(ecParams)) { var signBytes = ecdsa.SignData(Encoding.UTF8.GetBytes(unsignedToken), HashAlgorithmName.SHA512); string signature = Base64UrlEncode(signBytes); // 4. 拼接得到完整的Signed Client Assertion return $"{unsignedToken}.{signature}"; } }
注意事项
- 若你使用的.NET版本低于4.7.2,可引入
Microsoft.IdentityModel.Tokens和System.IdentityModel.Tokens.JwtNuget包,直接用封装好的JwtSecurityTokenHandler生成,不需要手动处理签名逻辑 - 确保
GetClaims()返回的声明符合认证方要求,通常需要包含iss、sub、aud、exp、iat、jti几个必填字段
内容的提问来源于stack exchange,提问作者Nivibaxi
相关产品推荐
相关产品推荐

