using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using F9WebAiTest.Domain.Entities.SYS.RBAC; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; namespace F9WebAiTest.Application.Services.Auth; public class JwtService : IJwtService { private readonly IConfiguration _config; public JwtService(IConfiguration config) { _config = config; } // 生成 access token(短期,如 2 小时) public string GenerateAccessToken(User user, IEnumerable roles) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var claims = new List { new("id", user.Id.ToString()), new(ClaimTypes.Name, user.LoginName), new("realName", user.UserName) }; foreach (var r in roles) { claims.Add(new Claim(ClaimTypes.Role, r)); } var expireMinutes = int.Parse(_config["Jwt:AccessTokenExpireMinutes"] ?? "120"); var token = new JwtSecurityToken( issuer: _config["Jwt:Issuer"], audience: _config["Jwt:Audience"], claims: claims, expires: DateTime.UtcNow.AddMinutes(expireMinutes), signingCredentials: creds ); return new JwtSecurityTokenHandler().WriteToken(token); } // 生成 refresh token(随机字符串,长期,如 7 天) public string GenerateRefreshToken() { var randomNumber = new byte[64]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(randomNumber); return Convert.ToBase64String(randomNumber); } public (long id, string username) ValidateAccessToken(string token) { var handler = new JwtSecurityTokenHandler(); var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var validationParams = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = key, ValidateIssuer = true, ValidIssuer = _config["Jwt:Issuer"], ValidateAudience = true, ValidAudience = _config["Jwt:Audience"], ValidateLifetime = true, ClockSkew = TimeSpan.Zero }; var principal = handler.ValidateToken(token, validationParams, out _); var id = long.Parse(principal.FindFirst("id")!.Value); var username = principal.Identity!.Name; return (id, username); } // 校验 refresh token 的签名(refresh token 也是 JWT,但只含 id claim) public long? ValidateRefreshToken(string token) { try { var handler = new JwtSecurityTokenHandler(); var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var validationParams = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = key, ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = false }; var principal = handler.ValidateToken(token, validationParams, out _); return long.Parse(principal.FindFirst("id")!.Value); } catch { return null; } } }