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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:22:54