使用Azure Key Vault验证JWT签名始终返回false的问题排查
问题诊断与修复方案
你的验证失败主要有两个关键问题:
1. 签名时错误地提前计算了哈希值
Azure Key Vault的SignAsync方法对于ES256这类算法,会自动对传入的数据进行SHA-256哈希,然后再执行ECDSA签名。但你在SignJwt方法中提前计算了数据的SHA-256 digest,然后把这个哈希值传给了SignAsync——这就相当于让Key Vault对“哈希的哈希”进行签名,最终生成的签名和原始数据的正确签名完全不匹配,自然无法通过验证。
2. 验证时错误地处理了签名字节数组
在ValidateJwt方法中,你使用Base64UrlEncoder.Decode得到签名的字符串,再用Encoding.UTF8.GetBytes转成字节数组。但签名是二进制数据,不是UTF-8编码的字符串,这样的转换会破坏原始签名的字节信息,导致验证时使用的签名数据和实际签名不一致。
修正后的代码
修复后的SignJwt方法
直接将原始的header + "." + token.EncodedPayload字节数组传给SignAsync,不需要提前计算哈希:
private static async Task<string> SignJwt(KeyVaultClient client) { var claimsToSign = new[] { new Claim("sub", "UserId123"), new Claim("custom", "MyValue") }; var token = new JwtSecurityToken( issuer: "AuthApp", audience: "Consumer", claims: claimsToSign ); var header = Base64UrlEncoder.Encode(JsonConvert.SerializeObject(new Dictionary<string, string>() { {JwtHeaderParameterNames.Alg, JsonWebKeySignatureAlgorithm.ES256}, {JwtHeaderParameterNames.Typ, "JWT"} })); // 直接使用原始数据字节,不提前计算哈希 var byteData = Encoding.UTF8.GetBytes(header + "." + token.EncodedPayload); var signature = await client.SignAsync(KeyVaultBaseUrl, KeyName, KeyVersion, JsonWebKeySignatureAlgorithm.ES256, byteData); var fullJwt = $"{header}.{token.EncodedPayload}.{Base64UrlEncoder.Encode(signature.Result)}"; return fullJwt; }
修复后的ValidateJwt方法
使用Base64UrlEncoder.DecodeBytes直接获取签名的原始字节数组,避免字符串转码错误:
private static async Task<KeyVerifyResult> ValidateJwt() { var jwt = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJVc2VySWQxMjMiLCJjdXN0b20iOiJNeVZhbHVlIiwiaXNzIjoiQXV0aEFwcCIsImF1ZCI6IkNvbnN1bWVyIn0.6tYkBcoFojJVJBhdNST49v4A3VWC1Rqizx_FzmSRICQubDEfXVopfP7Rs9tOBi9YzTCbod9o3hmHzIxANoIh7A"; var client = new KeyVaultClient(GetAccessTokenAsync, new HttpClient()); var jwtParts = jwt.Split('.'); var header = jwtParts[0]; var body = jwtParts[1]; // 直接解码为字节数组,不经过字符串转码 var signature = Base64UrlEncoder.DecodeBytes(jwtParts[2]); var byteData = Encoding.UTF8.GetBytes($"{header}.{body}"); var hasher = SHA256.Create(); // 替代过时的SHA256CryptoServiceProvider var digest = hasher.ComputeHash(byteData); var verified = await client.VerifyAsync(KeyVaultBaseUrl, KeyName, KeyVersion, JsonWebKeySignatureAlgorithm.ES256, digest, signature); return verified; }
另外补充:SHA256CryptoServiceProvider已被标记为过时,改用SHA256.Create()能提升代码的兼容性和安全性。
内容的提问来源于stack exchange,提问作者Barker1889
相关产品推荐
相关产品推荐

