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 // 不允许时间偏差
};
}
}