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));
}
}
}