[英]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.Jwt
和System.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.