使用 azure keyvault 验证 JWT 签名总是 returns false

Verifying a JWT signature using azure keyvault always returns false

我正在尝试使用 Azure keyvault 客户端验证签名,但它总是返回 false。

我已经设法使用 KeyVaultClient.SignAsync 方法对其进行签名,但是当尝试使用 KeyVaultClient.VerifyAsync 时,结果总是返回 false。

// Added for completeness, this method seems to be working correctly
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 hasher = new SHA256CryptoServiceProvider();
    var digest = hasher.ComputeHash(byteData);

    var signature = await client.SignAsync(KeyVaultBaseUrl, KeyName, KeyVersion, JsonWebKeySignatureAlgorithm.ES256, digest);

    var fullJwt = $"{header}.{token.EncodedPayload}.{Base64UrlEncoder.Encode(signature.Result)}";

    return fullJwt;
}

// This always returns a false result
private static async Task<KeyVerifyResult> ValidateJwt()
{
    // Example of a JWT produced by the SignJwt method
    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 = Encoding.UTF8.GetBytes(Base64UrlEncoder.Decode(jwtParts[2]));

    var byteData = Encoding.UTF8.GetBytes($"{header}.{body}");
    var hasher = new SHA256CryptoServiceProvider();
    var digest = hasher.ComputeHash(byteData);

    var verified = await client.VerifyAsync(KeyVaultBaseUrl, KeyName, KeyVersion, JsonWebKeySignatureAlgorithm.ES256, digest, signature);
    return verified;
}


private static async Task<string> GetAccessTokenAsync(string authority, string resource, string scope)
{
    var appCredentials = new ClientCredential(ClientId, ClientSecret);
    var context = new AuthenticationContext(authority, TokenCache.DefaultShared);

    var result = await context.AcquireTokenAsync(resource, appCredentials);

    return result.AccessToken;
}

知道为什么 ValidateJwt 总是 returns false 而不是 true 吗?

解决了。

对于任何感兴趣的人,我没有正确地对 SignJwt 方法中的签名进行 base 64 编码:

不使用 Base64UrlEncoder.Encode/Decode,而是使用 Convert.ToBase64String/FromBase64String


为了使问题中的代码片段正常工作,我需要将 SignJwt 和 ValidateJwt 方法更新为:

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 = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new Dictionary<string, string>()
    {
        {JwtHeaderParameterNames.Alg, JsonWebKeySignatureAlgorithm.ES256},
        {JwtHeaderParameterNames.Typ, "JWT"}
    })));

    var byteData = Encoding.UTF8.GetBytes(header + "." + token.EncodedPayload);
    var hasher = new SHA256CryptoServiceProvider();
    var digest = hasher.ComputeHash(byteData);

    var signature = await client.SignAsync(KeyVaultBaseUrl, KeyName, KeyVersion, JsonWebKeySignatureAlgorithm.ES256, digest);

    var fullJwt = $"{header}.{token.EncodedPayload}.{Base64UrlEncoder.Encode(signature.Result)}";

    return fullJwt;
}

private static async Task<KeyVerifyResult> ValidateJwt()
{
    // Example of a JWT produced by the SignJwt method
    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 = Encoding.UTF8.GetBytes(Convert.FromBase64String(jwtParts[2]));

    var byteData = Encoding.UTF8.GetBytes($"{header}.{body}");
    var hasher = new SHA256CryptoServiceProvider();
    var digest = hasher.ComputeHash(byteData);

    var verified = await client.VerifyAsync(KeyVaultBaseUrl, KeyName, KeyVersion, JsonWebKeySignatureAlgorithm.ES256, digest, signature);
    return verified;
}