using Entities.Configuration; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using Entities.DTO; namespace TechHelper.Services.Beta { /// /// 用户认证服务,实现 JWT 令牌生成、刷新令牌生成、过期令牌解析等功能。 /// public class AuthenticationService : IAuthenticationService { private readonly JwtConfiguration _jwtSettings; private readonly JwtSecurityTokenHandler _jwtHandler; private readonly UserManager _userManager; private readonly IClassService _classService; /// /// 构造函数,注入 JWT 配置、用户管理器和班级服务。 /// public AuthenticationService(IOptions jwtSettings, UserManager userManager, IClassService classService) { _jwtSettings = jwtSettings.Value; _jwtHandler = new JwtSecurityTokenHandler(); _userManager = userManager; _classService = classService; } /// /// 生成指定用户的 JWT 访问令牌。 /// /// 用户实体 /// JWT 字符串 public async Task GetToken(Entities.Contracts.User user) { var signingCredentials = GetSigningCredentials(); var claims = await GetClaims(user); var tokenOptions = GenerateTokenOptions(signingCredentials, claims); return _jwtHandler.WriteToken(tokenOptions); } /// /// 获取 JWT 签名凭证。 /// /// 签名凭证 private SigningCredentials GetSigningCredentials() { var key = Encoding.UTF8.GetBytes(_jwtSettings.SecurityKey); var secret = new SymmetricSecurityKey(key); return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256); } /// /// 获取用户的声明信息,包括角色和班级信息。 /// /// 用户实体 /// 声明集合 private async Task> GetClaims(Entities.Contracts.User user) { var claims = new List { new Claim(ClaimTypes.Name, user.Email) }; // 添加用户角色声明 var roles = await _userManager.GetRolesAsync(user); foreach (var role in roles) { claims.Add(new Claim(ClaimTypes.Role, role)); } #region ClassInfo // 添加用户班级信息声明 var classInfo = await _classService.GetUserInjoinedClasses(user.Id); if (classInfo.Status) { var classs = classInfo.Result as UserClassDetailInfoDto; if (classs == null) return claims; foreach (var c in classs.UserClassInfos) { claims.Add(new Claim("Grade", c.Grade.ToString())); claims.Add(new Claim("Class", c.Class.ToString())); } } #endregion return claims; } /// /// 生成 JWT 令牌对象。 /// /// 签名凭证 /// 声明集合 /// JWT 令牌对象 private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, IEnumerable claims) { var tokenOptions = new JwtSecurityToken( issuer: _jwtSettings.ValidIssuer, audience: _jwtSettings.ValidAudience, claims: claims, expires: DateTime.UtcNow.AddMinutes(Convert.ToDouble( _jwtSettings.ExpiryInMinutes)), signingCredentials: signingCredentials); return tokenOptions; } /// /// 生成安全的刷新令牌(Base64 字符串)。 /// /// 刷新令牌 public string GenerateRefreshToken() { var randomNumber = new byte[32]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(randomNumber); return Convert.ToBase64String(randomNumber); } } /// /// 从过期的 JWT 令牌中获取声明主体(不验证过期时间)。 /// /// 过期的 JWT 令牌 /// 声明主体 /// 令牌无效时抛出 public ClaimsPrincipal GetPrincipalFromExpiredToken(string token) { var tokenValidationParameters = new TokenValidationParameters { ValidateAudience = true, ValidateIssuer = true, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(_jwtSettings.SecurityKey)), ValidateLifetime = false, // 不验证过期时间 ValidIssuer = _jwtSettings.ValidIssuer, ValidAudience = _jwtSettings.ValidAudience, }; var tokenHandler = new JwtSecurityTokenHandler(); SecurityToken securityToken; var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken); var jwtSecurityToken = securityToken as JwtSecurityToken; if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) { throw new SecurityTokenException("Invalid token"); } return principal; } } }