【问题标题】:Verifying a JWT signature using azure keyvault always returns false使用 azure keyvault 验证 JWT 签名始终返回 false
【发布时间】:2019-11-28 09:03:13
【问题描述】:

我正在尝试使用 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 总是返回 false 而不是 true?

【问题讨论】:

    标签: c# jwt signing azure-keyvault


    【解决方案1】:

    解决了。

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

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


    为了使问题中的代码 sn-p 正常工作,我需要将 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;
    }
    

    【讨论】:

    • 很高兴您能够解决这个问题!你能把它标记为答案吗?
    • 您介意发布完整的正确代码吗?
    • @Leonardo 当然,我已将示例代码添加到我的答案中
    猜你喜欢
    • 1970-01-01
    • 2012-08-27
    • 1970-01-01
    • 1970-01-01
    • 2017-06-12
    • 2017-12-18
    • 1970-01-01
    • 2018-09-16
    • 2019-11-17
    相关资源
    最近更新 更多