Azure KeyVault - 签署 JWT 令牌

use*_*730 6 c# azure .net-core azure-keyvault asp.net-core

我开始使用 Azure Keyvault 为我的应用程序存储私钥。

我有一个用例,我需要使用 RSA 私钥对 JWT 令牌进行签名。

当我的应用程序内存中有私钥时,这很容易,我会这样做

var token = new JwtSecurityToken(
                issuer,
                ...,
                claims,
                ...,
                ...,
                signingCredentials_PrivateKey);
Run Code Online (Sandbox Code Playgroud)

既然开始使用Azure Keyvault,我想看看是否可以通过该KeyVaultClient.SignAsync方法对JWT令牌进行签名。

类似的东西

KeyVaultClient client = ...;
var token = new JwtSecurityToken(
                issuer,
                ...,
                claims,
                ...,
                ...);
var tokenString = client.SignAsync(myKeyIdentifier, token);
Run Code Online (Sandbox Code Playgroud)

Jac*_*Jia 9

首先,JWT 令牌由三部分组成:Header、Payload 和 Signature。它们都是 Base64UrlEncoded。

您可以通过以下方式获得签名:

HMAC-SHA256(
 base64urlEncoding(header) + '.' + base64urlEncoding(payload),
 secret
)
Run Code Online (Sandbox Code Playgroud)

因此,您需要生成标头和有效负载,将它们按点组合,计算散列,然后才能获得签名。

这是一个示例供您参考:

var byteData = Encoding.Unicode.GetBytes(base64urlEncoding(header) + "." + base64urlEncoding(payload));
var hasher = new SHA256CryptoServiceProvider();
var digest = hasher.ComputeHash(byteData);
var signature = await keyClient.SignAsync(keyIdentifier, "RS256", digest);
var token = base64urlEncoding(header) + "." + base64urlEncoding(payload) + "." + base64urlEncoding(signature)
Run Code Online (Sandbox Code Playgroud)

SignAsync的官方 SDK 文档

JWT 的Wiki


use*_*730 5

我最终使用了杰克贾的答案

var token = new JwtSecurityToken(
                issuer,
                appId,
                claims,
                signDate,
                expiryDate);

var header = Base64UrlEncoder.Encode(JsonConvert.SerializeObject(new Dictionary<string, string>()
{
    { JwtHeaderParameterNames.Alg, "RS256" },
    { JwtHeaderParameterNames.Kid, "https://myvault.vault.azure.net/keys/mykey/keyid" },
    { JwtHeaderParameterNames.Typ, "JWT" }
}));
var byteData = Encoding.UTF8.GetBytes(header + "." + token.EncodedPayload);
var hasher = new SHA256CryptoServiceProvider();
var digest = hasher.ComputeHash(byteData);
var signature = await _keyVault.SignAsync("https://myvault.vault.azure.net/keys/mykey/keyid", "RS256", digest);

return $"{header}.{token.EncodedPayload}.{Base64UrlEncoder.Encode(signature.Result)}";
Run Code Online (Sandbox Code Playgroud)

我找到了另一个解决方案,我不太喜欢它,但它与 JWT 库更好地“集成”。

var token = new JwtSecurityToken(
    issuer,
    appId,
    claims,
    signDate,
    expiryDate,
    new SigningCredentials(new KeyVaultSecurityKey("https://myvault.vault.azure.net/keys/mykey/keyid", new KeyVaultSecurityKey.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback)), "RS256")
    {
        CryptoProviderFactory = new CryptoProviderFactory() { CustomCryptoProvider = new KeyVaultCryptoProvider() }
    });

var handler = new JwtSecurityTokenHandler();
return handler.WriteToken(token);
Run Code Online (Sandbox Code Playgroud)

事实证明,有一个Microsoft.IdentityModel.KeyVaultExtensions扩展SecurityTokenICryptoProvider支持 KeyVault 的库。

我的问题是

  1. 我无法使用KeyVaultClient此解决方案重用现有实例。
  2. 它的阻止(在幕后,它调用.GetAwaiter().GetResult()KeyVaultClient.SignAsync