繁体   English   中英

验证 JWT 令牌签名的最简单方法是什么?

[英]What is the easiest way to validate the signature of a JWT token?

首先是一些代码......我有一个安全 class:

public static class Security
{
    public static RSACryptoServiceProvider RSA { get; } = new(4096);
    public static SigningCredentials Credentials()
    {
        return new SigningCredentials(new RsaSecurityKey(RSA), SecurityAlgorithms.RsaSha512)
        {
            CryptoProviderFactory = new CryptoProviderFactory { CacheSignatureProviders = false }
        };
    }

}

这是一个简单的 static class 生成 RSA 密钥和相关的签名凭证。 它有更多代码,但这对我的问题并不重要......
然后我有代码使用System.IdentityModel.Tokens.JwtSystem.Security.Claims生成 JWT 令牌:

    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Jti, account.Id.ToString()),
        new Claim(JwtRegisteredClaimNames.Sub, account.Name),
        new Claim(JwtRegisteredClaimNames.Name, account.FullName),
        new Claim(JwtRegisteredClaimNames.GivenName, account.FirstName),
        new Claim(JwtRegisteredClaimNames.FamilyName, account.LastName),
        new Claim(JwtRegisteredClaimNames.Birthdate, account.Birthdate.ToString()),
        new Claim(JwtRegisteredClaimNames.Email, account.Email.ToString()),
    };
    var token = new JwtSecurityToken
    (
        issuer: host,
        audience: audience,
        claims: claims,
        notBefore: DateTime.UtcNow,
        expires: DateTime.UtcNow.AddHours(4),
        Security.Credentials()
    );

再次,不是太具有挑战性。 我的代码中的一些数据声明,这是我自己的 class 和基本用户数据。 这变成了一个签名的令牌。 它产生了这个令牌:

eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhYmQ3NjUxMS1jNmNmLTQzZjUtOGE1Zi1iZjEzZTg0NGM1ZmEiLCJzdWIiOiJ3aW0iLCJuYW1lIjoiV2ltIFRlbiBCcmluayIsImdpdmVuX25hbWUiOiJXaW0iLCJmYW1pbHlfbmFtZSI6IlRlbiBCcmluayIsImJpcnRoZGF0ZSI6IjExLTctMTk2NiIsImVtYWlsIjoid2ltQGV4YW1wbGUuY29tIiwibmJmIjoxNjQwNjU1MDA1LCJleHAiOjE2NDA2Njk0MDUsImlzcyI6ImxvY2FsaG9zdDo3MTkwIiwiYXVkIjoiL1Rva2VuL0xvZ2luIn0.iFn6DKvHxW_Vd6bxlLs4quQwCyYWpL7bbyMJSTVMxS4RRQ9GxM9IvgoymEqyn9YNBc68TFULNPRVBFE8_mF-IpYt1NIGtp8p7u9laMRegEfXyvJFislDcPZoMbD5xjB18xwUwTpkNjdX4svzFIR8mQT5bLcb5BojFLhxUVT-oJ8G_f0lD0XWJkDo40OW9aHECjIOOu_KfeYZiPdiuo-q9yed6WN1-dgqz4ykWOYC7FoMA0ZYogG5pRvmVLOq8haiEDEJRszbhjj6CLt6h_hlwOS0mMZF6a7Ag5mN4lI2UtEot-jYyXM72eXgBPm_bWNsa6RG_m9vFf4EElK4ekfFd3V_qkAnZ8XEhfTcRD8ASEVjXg8hTI5SY4LFyrggso44HFN5oEoVWlVVcGZxEG2R6LspJSFD4xkrVUUeQvt7IbBL1ViflSfGYp6-cLMPfxo3qZvItC7DxP_8aAygNmHi0_T8BxGNLnOwqrPtDOjKzw4SqEEwBf5S5R6O_dufhauAVvvS_rKQnkEdq-MNNNW5U90ytauCcAgFEGa03MN3E4hhQKUE5y70wCStrIFcBtJezf32U8V7SHv1WrVMpnQXxQoLneZh3b7QsthKCh49ypUSLjw 4yL9VVur2K0oV8NsLnwoqH5dCVFuq7YHmreiTa-ZUIFVrgWYMzMqR8hG7Ato

现在我想使用以下代码将其转换回令牌:

var tokenData = new JwtSecurityToken(tokenString);

这将再次从字符串生成令牌,但它当然没有经过验证。 我需要验证这个令牌的签名。
需要明确的是:这不适用于 ASP.NET 核心应用程序,但我确实将 .NET 核心用于此控制台应用程序。 这是一个简单的工具,它连接到包含字符串形式的令牌的数据库,它只需要使用特定的 RSA 密钥验证其中的每个令牌。 (也存储在安全位置。)此数据库中的令牌来自 web 应用程序,该应用程序使用此表进行日志记录,但显然某些令牌使用错误或无效的密钥进行签名,我需要一种快速方法来查找哪些令牌在这个日志。

那么,验证这些签名的最简单方法是什么?


还有一个更新:我的代码正在使用Microsoft.AspNetCore.Authentication.JwtBearer ,由于某种原因,它在验证过程中导致了一些意外行为和错误。 当我将它踢出并用System.IdentityModel.Tokens.Jwt替换它时,一切都开始工作了。
这两个包在类和其他部分非常相似,我不确定它们之间有何不同,但它们确实不同。 一种是使用 OpenID,另一种是使用 JWT。 切换到最后一个解决了我的问题...

如果您不限于语言,您可以使用我们在 Curity 创建的用于验证 JWT 的库: https://www.npmjs.com/package/@curity/jwt-validation 我们还创建了一个可用于验证 JWT 的库列表: https://curity.io/resources/guides/libraries/api/所以如果你想坚持使用 .NET,你可以在那里找到一个库。 我们还有一个教程展示了如何使用 .NET 库: https://curity.io/resources/learn/dotnet-api/

事实证明,这似乎是 package Microsoft.AspNetCore.Authentication.JwtBearer 中的错误,但 package System.IdentityModel.Tokens.Z74334B5D32B195AB49ZDAC2D35 已完成以下代码有效:

        var param = new TokenValidationParameters
        {
            ClockSkew = TimeSpan.FromMinutes(5),
            ValidateAudience = true,
            ValidateIssuer = true,
            ValidateIssuerSigningKey = true,
            ValidateTokenReplay = false,
            ValidateLifetime = true,
            IssuerSigningKey = new RsaSecurityKey(Security.RSA),
            ValidAudience = Audience,
            ValidIssuer = Issuer,
        };
        var claim = new JwtSecurityTokenHandler().ValidateToken(tokenString, param, out _);
        if (claim == null) throw new InvalidSignature(tokenString);

(但是承载库失败了。不知道为什么。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM