using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using AmtScanner.Api.Configuration; using AmtScanner.Api.Models; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; namespace AmtScanner.Api.Services; /// /// JWT 服务实现 /// public class JwtService : IJwtService { private readonly JwtSettings _settings; private readonly SymmetricSecurityKey _securityKey; public JwtService(IOptions settings) { _settings = settings.Value; _securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.SecretKey)); } public string GenerateAccessToken(User user, IEnumerable roles) { var claims = new List { new(ClaimTypes.NameIdentifier, user.Id.ToString()), new(ClaimTypes.Name, user.UserName), new("userId", user.Id.ToString()), new("userName", user.UserName) }; // 添加角色 claims foreach (var role in roles) { claims.Add(new Claim(ClaimTypes.Role, role)); claims.Add(new Claim("roles", role)); } // 添加邮箱(如果有) if (!string.IsNullOrEmpty(user.Email)) { claims.Add(new Claim(ClaimTypes.Email, user.Email)); } var credentials = new SigningCredentials(_securityKey, SecurityAlgorithms.HmacSha256); var expires = DateTime.UtcNow.AddMinutes(_settings.AccessTokenExpirationMinutes); var token = new JwtSecurityToken( issuer: _settings.Issuer, audience: _settings.Audience, claims: claims, expires: expires, signingCredentials: credentials ); return new JwtSecurityTokenHandler().WriteToken(token); } public string GenerateRefreshToken() { var randomBytes = new byte[64]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(randomBytes); return Convert.ToBase64String(randomBytes); } public ClaimsPrincipal? ValidateToken(string token) { var tokenHandler = new JwtSecurityTokenHandler(); try { var principal = tokenHandler.ValidateToken(token, GetValidationParameters(), out _); return principal; } catch { return null; } } public ClaimsPrincipal? GetPrincipalFromExpiredToken(string token) { var tokenHandler = new JwtSecurityTokenHandler(); try { var validationParameters = GetValidationParameters(); validationParameters.ValidateLifetime = false; // 不验证过期时间 var principal = tokenHandler.ValidateToken(token, validationParameters, out var securityToken); if (securityToken is not JwtSecurityToken jwtToken || !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) { return null; } return principal; } catch { return null; } } public DateTime GetRefreshTokenExpiryTime() { return DateTime.UtcNow.AddDays(_settings.RefreshTokenExpirationDays); } private TokenValidationParameters GetValidationParameters() { return new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = _settings.Issuer, ValidAudience = _settings.Audience, IssuerSigningKey = _securityKey, ClockSkew = TimeSpan.Zero // 不允许时间偏差 }; } }