Qua*_*023 5 c# jwt asp.net-core-webapi .net-8.0
我刚刚将 ASP.NET Core 6 Web API 升级到 .NET 8(请注意,在 .NET 6 中一切都工作得很好),并且在创建 JWT 令牌时收到此错误:
System.ArgumentOutOfRangeException:'IDX10720:无法为算法'HS256'创建KeyedHashAlgorithm,密钥大小必须大于:'256'位,密钥具有'152'位。(参数'keyBytes')'
根据我对此错误的理解,似乎对秘密需要多长时间有一个新的要求,因此我使秘密更长,这适用于创建令牌,但在读取令牌时我收到一个全新的错误
System.ArgumentException:“IDX12723:无法解码有效负载”[“System.String”类型的 PII 已隐藏。有关更多详细信息,请参阅 https://aka.ms/IdentityModel/PII。]' 作为 Base64Url 编码字符串。
编辑:这是内部异常,也许这可以说明一些问题
JsonException:IDX11020:类型为“String”的 JSON 值无法转换为“JsonTokenType.Number”。读取:“System.IdentityModel.Tokens.Jwt.JwtPayload.iat”,位置:“52”,当前深度:“1”,消耗的字节数:“75”。
这里是否有一些处理 JWT 令牌的重大更改?
这是读取令牌的私有方法的代码
private User? _GetIdentity(HttpContext context, string token)
{
try
{
var handler = new JwtSecurityTokenHandler();
//var jsonToken = handler.ReadToken(token);
var tokenS = handler.ReadToken(token) as JwtSecurityToken;//error happens here
var user = new User
{
Id = tokenS.Claims.First(claim => claim.Type == ClaimTypes.NameIdentifier).Value,
UserName = tokenS.Claims.First(claim => claim.Type == ClaimTypes.Name).Value,
Email = tokenS.Claims.First(claim => claim.Type == ClaimTypes.Email).Value,
Role = tokenS.Claims.First(claim => claim.Type == ClaimTypes.Role).Value
};
if (tokenS.ValidTo < DateTime.UtcNow)
{
throw new Exceptions.UnauthorizedAccessException($"...");
}
return user;
}
catch(Exceptions.UnauthorizedAccessException e)
{
_logger.LogError(e.Message);
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
以下是生成 JWT 令牌的类的代码:
public class JwtService
{
private const int EXPIRATION_TOKEN_MINUTES = 25;
private const int EXPIRATION_REFRESH_DAYS = 7;
private readonly IConfiguration _configuration;
public JwtService(IConfiguration configuration)
{
_configuration = configuration;
}
public AuthenticationResponse CreateToken(IdentityUser user, IEnumerable<string> roles)
{
var expiration = DateTime.Now.AddMinutes(EXPIRATION_TOKEN_MINUTES);
var refreshExpiration = DateTime.Now.AddDays(EXPIRATION_REFRESH_DAYS);
var token = CreateJwtToken(
CreateClaims(user, roles),
CreateSigningCredentials(),
expiration
);
var refreshToken = CreateJwtToken(
CreateRefreshTokenClaims(user.Id),
CreateSigningCredentials(),
refreshExpiration
);
var tokenHandler = new JwtSecurityTokenHandler();
return new AuthenticationResponse
{
Token = tokenHandler.WriteToken(token),
RefreshToken = tokenHandler.WriteToken(refreshToken),
Expiration = expiration
};
}
private JwtSecurityToken CreateJwtToken(Claim[] claims, SigningCredentials credentials, DateTime expiration) =>
new JwtSecurityToken(
_configuration["Jwt:Issuer"],
_configuration["Jwt:Audience"],
claims,
expires: expiration,
signingCredentials: credentials
);
private Claim[] CreateRefreshTokenClaims(string userId) =>
new[]
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.ToString()),
new Claim(ClaimTypes.NameIdentifier, userId)
};
private Claim[] CreateClaims(IdentityUser user, IEnumerable<string> roles) =>
new[] {
//new Claim(JwtRegisteredClaimNames.Sub, _configuration["Jwt:Subject"]),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Email, user.Email),
}
.Concat(roles.Select(r => new Claim(ClaimTypes.Role, r)).ToArray())
.ToArray();
private SigningCredentials CreateSigningCredentials() =>
new SigningCredentials(
new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_configuration["Jwt:Secret"])
),
SecurityAlgorithms.HmacSha256
);
public ClaimsIdentity CreateClaimsIdentity(string username, string userId, IEnumerable<string> roles)
{
List<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.NameIdentifier, userId)
};
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
ClaimsIdentity identity = new ClaimsIdentity(
claims,
"Token",
ClaimTypes.Name,
ClaimTypes.Role
);
return identity;
}
public ClaimsPrincipal ValidateToken(string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
// Set the token validation parameters
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidAudience = _configuration["Jwt:Audience"],
ValidIssuer = _configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_configuration["Jwt:Secret"])
)
};
// Validate and parse the token
var principal = tokenHandler.ValidateToken(token, validationParameters, out var _);
return principal;
}
catch
{
// Token validation failed
return null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 3
我有完全相同的问题。
JWT 字段 Iat 应该是一个数字(自 1970 年 1 月 1 日以来的秒数)
生成 JWT 时,只需替换:
claims.Add(new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString())),
Run Code Online (Sandbox Code Playgroud)
和:
long iat = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
claims.Add(new Claim(JwtRegisteredClaimNames.Iat, iat.ToString()));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1427 次 |
| 最近记录: |