简体   繁体   English

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

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

First some code... I have a Security class:首先是一些代码......我有一个安全 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 }
        };
    }

}

This is a simple static class that generates an RSA key and related signing credentials.这是一个简单的 static class 生成 RSA 密钥和相关的签名凭证。 It has some more code but that's not important for my question...它有更多代码,但这对我的问题并不重要......
Then I have code to generate a JWT token using System.IdentityModel.Tokens.Jwt and System.Security.Claims :然后我有代码使用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()
    );

Again, not too challenging.再次,不是太具有挑战性。 A few claims from data in my code, which is my own class with basic user data.我的代码中的一些数据声明,这是我自己的 class 和基本用户数据。 And this is turned into a token that is signed.这变成了一个签名的令牌。 It results in this token:它产生了这个令牌:

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

And now I want to convert it back to a token by using this code:现在我想使用以下代码将其转换回令牌:

var tokenData = new JwtSecurityToken(tokenString);

And that will generate the token from the string again, but it's not verified, of course.这将再次从字符串生成令牌,但它当然没有经过验证。 And I need to verify the signature for this token.我需要验证这个令牌的签名。
To be clear: this is NOT for an ASP.NET Core application but I do use .NET Core for this console application.需要明确的是:这不适用于 ASP.NET 核心应用程序,但我确实将 .NET 核心用于此控制台应用程序。 This is a simple tool that connects to a database which contains tokens as strings and it just has to validate every token inside it with a specific RSA key.这是一个简单的工具,它连接到包含字符串形式的令牌的数据库,它只需要使用特定的 RSA 密钥验证其中的每个令牌。 (Also stored in a safe location.) Tokens in this database come from a web application which uses this table for logging purposes but apparently some tokens get signed with a wrong or invalid key and I need a quick way to find which tokens are invalid in this log. (也存储在安全位置。)此数据库中的令牌来自 web 应用程序,该应用程序使用此表进行日志记录,但显然某些令牌使用错误或无效的密钥进行签名,我需要一种快速方法来查找哪些令牌在这个日志。

So, what is the easiest way to validate these signatures?那么,验证这些签名的最简单方法是什么?


And an update: My code is using Microsoft.AspNetCore.Authentication.JwtBearer and for some reason it caused some unexpected behavior and errors during validations.还有一个更新:我的代码正在使用Microsoft.AspNetCore.Authentication.JwtBearer ,由于某种原因,它在验证过程中导致了一些意外行为和错误。 When I kicked it out and replaced it withSystem.IdentityModel.Tokens.Jwt it all starts to work.当我将它踢出并用System.IdentityModel.Tokens.Jwt替换它时,一切都开始工作了。
Both packages are very similar in classes and other parts, and I'm not sure how they differ from one another, but they do differ.这两个包在类和其他部分非常相似,我不确定它们之间有何不同,但它们确实不同。 One is to work with OpenID and the other one for JWT in general.一种是使用 OpenID,另一种是使用 JWT。 Switching to the last one solved my problems...切换到最后一个解决了我的问题...

If you're not limited to the language, you can use a library that we created at Curity for validating JWTs: https://www.npmjs.com/package/@curity/jwt-validation .如果您不限于语言,您可以使用我们在 Curity 创建的用于验证 JWT 的库: https://www.npmjs.com/package/@curity/jwt-validation We've also created a list of libraries which you can use to validate JWTs: https://curity.io/resources/guides/libraries/api/ so if you want to stick to .NET you can find a library there.我们还创建了一个可用于验证 JWT 的库列表: https://curity.io/resources/guides/libraries/api/所以如果你想坚持使用 .NET,你可以在那里找到一个库。 We also have a tutorial which shows how to use that .NET lib: https://curity.io/resources/learn/dotnet-api/我们还有一个教程展示了如何使用 .NET 库: https://curity.io/resources/learn/dotnet-api/

As it turns out, it seems to be a bug in package Microsoft.AspNetCore.Authentication.JwtBearer but the package System.IdentityModel.Tokens.Jwt is near-identical but got the job done.事实证明,这似乎是 package Microsoft.AspNetCore.Authentication.JwtBearer 中的错误,但 package System.IdentityModel.Tokens.Z74334B5D32B195AB49ZDAC2D35 已完成The following code just works:以下代码有效:

        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);

(But with the Bearer library ir failed. Not sure why.) (但是承载库失败了。不知道为什么。)

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

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