using System; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using Microsoft.IdentityModel.Tokens; namespace OpenAuth.App.SSO { /// /// JWT Token辅助类,用于本地认证模式下的Token生成和验证 /// public static class JwtTokenHelper { /// /// 生成JWT Token /// /// 用户账号 /// 用户名称 /// 应用标识 /// 会话ID,用作缓存Key /// JWT签名密钥 /// 过期天数 /// JWT Token字符串 public static string GenerateToken(string account, string name, string appKey, string sessionId, string secret, int expireDays = 10) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(EnsureKeyLength(secret))); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, account), new Claim(JwtRegisteredClaimNames.Jti, sessionId), new Claim("name", name ?? string.Empty), new Claim("app_key", appKey ?? string.Empty), }; var token = new JwtSecurityToken( issuer: "OpenAuth", audience: "OpenAuth", claims: claims, expires: DateTime.UtcNow.AddDays(expireDays), signingCredentials: credentials ); return new JwtSecurityTokenHandler().WriteToken(token); } /// /// 验证JWT Token并返回ClaimsPrincipal /// /// JWT Token字符串 /// JWT签名密钥 /// 验证成功返回ClaimsPrincipal,失败返回null public static ClaimsPrincipal ValidateToken(string token, string secret) { if (string.IsNullOrEmpty(token)) return null; var tokenHandler = new JwtSecurityTokenHandler(); var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(EnsureKeyLength(secret))); try { var validationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = key, ValidateIssuer = true, ValidIssuer = "OpenAuth", ValidateAudience = true, ValidAudience = "OpenAuth", ValidateLifetime = true, ClockSkew = TimeSpan.FromMinutes(5) }; var principal = tokenHandler.ValidateToken(token, validationParameters, out _); return principal; } catch { return null; } } /// /// 从JWT Token中提取会话ID(jti) /// public static string GetSessionId(string token) { var principal = ReadTokenWithoutValidation(token); return principal?.FindFirst(JwtRegisteredClaimNames.Jti)?.Value; } /// /// 从JWT Token中提取用户账号(sub) /// public static string GetAccount(string token) { var principal = ReadTokenWithoutValidation(token); return principal?.FindFirst(JwtRegisteredClaimNames.Sub)?.Value ?? principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value; } /// /// 不验证签名,仅读取Token中的Claims(用于快速提取信息) /// private static ClaimsPrincipal ReadTokenWithoutValidation(string token) { if (string.IsNullOrEmpty(token)) return null; try { var tokenHandler = new JwtSecurityTokenHandler(); if (!tokenHandler.CanReadToken(token)) return null; var jwtToken = tokenHandler.ReadJwtToken(token); var identity = new ClaimsIdentity(jwtToken.Claims); return new ClaimsPrincipal(identity); } catch { return null; } } /// /// 确保密钥长度至少为32字节(256位),不足时进行填充 /// private static string EnsureKeyLength(string secret) { if (string.IsNullOrEmpty(secret)) secret = "openauth_default_jwt_secret_key_2024"; // HMAC-SHA256要求密钥至少128位(16字节),建议256位(32字节) while (secret.Length < 32) { secret += secret; } return secret.Substring(0, Math.Max(32, secret.Length)); } } }