【问题标题】:What is the easiest way to validate the signature of a JWT token?验证 JWT 令牌签名的最简单方法是什么?
【发布时间】:2022-01-26 19:18:09
【问题描述】:

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

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

}

这是一个简单的静态类,可生成 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()
    );

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

eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhYmQ3NjUxMS1jNmNmLTQzZjUtOGE1Zi1iZjEzZTg0NGM1ZmEiLCJzdWIiOiJ3aW0iLCJuYW1lIjoiV2ltIFRlbiBCcmluayIsImdpdmVuX25hbWUiOiJXaW0iLCJmYW1pbHlfbmFtZSI6IlRlbiBCcmluayIsImJpcnRoZGF0ZSI6IjExLTctMTk2NiIsImVtYWlsIjoid2ltQGV4YW1wbGUuY29tIiwibmJmIjoxNjQwNjU1MDA1LCJleHAiOjE2NDA2Njk0MDUsImlzcyI6ImxvY2FsaG9zdDo3MTkwIiwiYXVkIjoiL1Rva2VuL0xvZ2luIn0.iFn6DKvHxW_Vd6bxlLs4quQwCyYWpL7bbyMJSTVMxS4RRQ9GxM9IvgoymEqyn9YNBc68TFULNPRVBFE8_mF-IpYt1NIGtp8p7u9laMRegEfXyvJFislDcPZoMbD5xjB18xwUwTpkNjdX4svzFIR8mQT5bLcb5BojFLhxUVT-oJ8G_f0lD0XWJkDo40OW9aHECjIOOu_KfeYZiPdiuo-q9yed6WN1-dgqz4ykWOYC7FoMA0ZYogG5pRvmVLOq8haiEDEJRszbhjj6CLt6h_hlwOS0mMZF6a7Ag5mN4lI2UtEot-jYyXM72eXgBPm_bWNsa6RG_m9vFf4EElK4ekfFd3V_qkAnZ8XEhfTcRD8ASEVjXg8hTI5SY4LFyrggso44HFN5oEoVWlVVcGZxEG2R6LspJSFD4xkrVUUeQvt7IbBL1ViflSfGYp6-cLMPfxo3qZvItC7DxP_8aAygNmHi0_T8BxGNLnOwqrPtDOjKzw4SqEEwBf5S5R6O_dufhauAVvvS_rKQnkEdq-MNNNW5U90ytauCcAgFEGa03MN3E4hhQKUE5y70wCStrIFcBtJezf32U8V7SHv1WrVMpnQXxQoLneZh3b7QsthKCh49ypUS Ljw4yL9VVur2K0oV8NsLnwoqH5dCVFuq7YHmreiTa-ZUIFVrgWYMzMqR8hG7Ato

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

var tokenData = new JwtSecurityToken(tokenString);

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

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


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

【问题讨论】:

  • 仅供参考,从 2011 年开始,Google 显示了太多选项,并且许多使用过时的功能或第三方软件包,它们不再那么好用了。 (或者对于 .NET 核心是否已过时...)
  • 这能回答你的问题吗? c# How to verify signature JWT?
  • @Progman 不,这是一个早于 .NET Core 的旧解决方案并且不起作用。另外,感觉现在是否应该存在更简单的方法。
  • edit 您的问题包含您遇到的问题的 MCVE。使用JwtSecurityTokenHandler.ValidateToken() 效果很好,请参阅dotnetfiddle.net/8GGlR4
  • @Progman 这个问题已经有足够的例子了。至于那个.NET Fiddle链接:我明白了:找不到方法:'Void Microsoft.IdentityModel.Tokens.InternalValidators.ValidateLifetimeAndIssuerAfterSignatureNotValidatedJwt(Microsoft.IdentityModel.Tokens.SecurityToken,System.Nullable1<System.DateTime>,System.Nullable1,System .String,Microsoft.IdentityModel.Tokens.TokenValidationParameters,System.Text.StringBuilder)”。 那么为什么会出现这个异常?

标签: c# .net-core jwt .net-6.0


【解决方案1】:

如果您不限于语言,您可以使用我们在 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/

【讨论】:

  • 这个项目我坚持使用 C#,因为数据库访问是通过实体框架进行的。此外,所提供的链接均未显示在 C# 中验证令牌签名的任何方式。
  • 啊,对不起。解决了那个 .NET 的问题...
【解决方案2】:

事实证明,这似乎是包 Microsoft.AspNetCore.Authentication.JwtBearer 中的一个错误,但包 System.IdentityModel.Tokens.Jwt 几乎相同,但完成了工作。以下代码有效:

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

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

【讨论】:

    猜你喜欢
    • 2019-11-01
    • 2017-05-04
    • 2016-11-17
    • 2018-05-29
    • 2017-09-18
    • 2020-05-11
    • 2018-11-28
    • 2019-06-14
    • 2018-11-25
    相关资源
    最近更新 更多