asp.net-core - 如何在 dotnet core 中验证非对称签名的 JWT?

标签 asp.net-core .net-core jwt rsa

我找到了 .NET FW 中的非对称签名示例和 .NET Core 中的对称签名示例,但我无法弄清楚如何在 .NET Core 中非对称地验证 JWT。给定 JWK 集的 URL 或给定公钥,如何在 .NET Core 中验证 token ?

最佳答案

A Symmetric Signing 和 Symmetric Signing 之间的唯一区别是签名 key 。只需为 token 验证参数构造一个新的非对称安全 key 即可。

假设您想使用 RSA 算法。让我们使用 powershell 导出一对 RSA key ,如下所示:

$rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider -ArgumentList 2048

$rsa.ToXmlString($true) | Out-File key.private.xml
$rsa.ToXmlString($false) | Out-File key.public.xml

现在我们将使用这两个 key 对 token 进行签名。

一点修补

由于rsa.FromXmlString() api受.NET Core支持,我只是复制@myloveCc's code构建 RsaParameters在 C# 中(这项工作通过以下 ParseXmlString() 方法完成):

public static class KeyHelper 
{
    public static RSAParameters ParseXmlString( string xml){
        RSAParameters parameters = new RSAParameters();

        System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
        xmlDoc.LoadXml(xml);

        if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
        {
            foreach (System.Xml.XmlNode node in xmlDoc.DocumentElement.ChildNodes)
            {
                switch (node.Name)
                {
                    case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                }
            }
        }
        else
        {
            throw new Exception("Invalid XML RSA key.");
        }
        return parameters;
    }


    public static RsaSecurityKey BuildRsaSigningKey(string xml){ 
        var parameters = ParseXmlString(xml);
        var rsaProvider = new RSACryptoServiceProvider(2048);
        rsaProvider.ImportParameters(parameters);
        var key = new RsaSecurityKey(rsaProvider);   
        return key;
    }  
}

这里我添加一个 BuildRsaSigningKey()生成 SecurityKey 的辅助方法.

代币生成

这是一个使用 RSA 生成 token 的演示:


public string GenerateToken(DateTime expiry)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var Identity = new ClaimsIdentity(new[]
    {
        new Claim(ClaimTypes.Name,          "..."),
        // ... other claims
   });

    var xml = "<RSAKeyValue> load...from..local...files...</RSAKeyValue>";
    SecurityKey key =  KeyHelper.BuildRsaSigningKey(xml); 

    var Token = new JwtSecurityToken
    (
        issuer: "test",
        audience: "test-app",
        claims: Identity.Claims,
        notBefore: DateTime.UtcNow,
        expires: expiry,
        signingCredentials: new SigningCredentials(key, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest)
    );
    var TokenString = tokenHandler.WriteToken(Token);
    return TokenString;
}

token 验证

要自动验证它,请配置 JWT Bearer 身份验证,如下所示:

Services.AddAuthentication(A =>
{
    A.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    A.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(O =>
{
    var xml = "<RSAKeyValue> load...from..local...files...</RSAKeyValue>";
    var key = KeyHelper.BuildRsaSigningKey(xml);

    O.RequireHttpsMetadata = false;
    O.SaveToken = true;
    O.IncludeErrorDetails = true;
    O.TokenValidationParameters = new TokenValidationParameters
    {
        IssuerSigningKey = key,
        ValidateIssuerSigningKey = true,
        ValidateLifetime = true,   
        // ... other settings
    };
});

如果您想手动验证它:

public IActionResult ValidateTokenManually(string jwt)
{
    var xml = "<RSAKeyValue>... the keys ...</RSAKeyValue>";
    SecurityKey key = KeyHelper.BuildRsaSigningKey(xml);    

    var validationParameters = new TokenValidationParameters
    {
        IssuerSigningKey = key,
        RequireSignedTokens = true,
        RequireExpirationTime = true,
        ValidateLifetime = true,
        // ... other settings
    };

    var tokenHandler = new JwtSecurityTokenHandler();
    var principal = tokenHandler.ValidateToken(jwt, validationParameters, out var rawValidatedToken);
    var securityToken = (JwtSecurityToken)rawValidatedToken;
    return Ok(principal);
}

关于asp.net-core - 如何在 dotnet core 中验证非对称签名的 JWT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56696254/

相关文章:

templates - 在 dotnet 新模板中包含 "hidden"文件

angular - 以 Angular 验证 jwt?

Laravel JWT AUTH 仅返回 TRUE/FALSE

sql-server - MARS TDS header 包含错误 - ASP.NET Core + EF Core 2.1.4 + Azure SQL Server

c# - EF Core 无法在表中插入标识列的显式值

c# - ASP.NET Core Web App 将 404 请求记录为警告

azure-web-app-service - ASP.NET 5 Beta7 不再在 Azure 网站上运行

azure - 从本地开发中的应用程序配置访问 Azure Key Vault 引用值

c# - 使用 Blazor 实现带有刷新 token 的短暂 Jwt

.net-core - 在 Visual Studio 2017 中启动操作 : Don't open page with . NET Core