Files
zszq-trs/YLErpDAL/Helpers/AuthHelper.cs
T
hjhan f182b880c1 feat(auth): 实现JWT令牌黑名单机制
- 在退出登录时清除JWT Token Cookie并将其加入黑名单
- 添加JTI声明到JWT令牌用于唯一标识和黑名单管理
- 在中间件中验证令牌时检查黑名单状态并拒绝已注销的令牌
- 实现令牌立即失效功能防止已退出用户继续访问系统
2026-03-23 17:52:15 +08:00

107 lines
3.6 KiB
C#

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using YLErp;
namespace YLErp.Helpers
{
/// <summary>
/// 用户认证帮助类
/// </summary>
public class AuthHelper
{
public const string CookieAuthType = "yc_identity";
public const string JwtAuthType = "yc_mapi";
/// <summary>
/// 登录Token过期时间(秒)
/// </summary>
public static int ExpireInSeconds => PS.Config?.ErpElement?.LoginTokenExpireSeconds ?? 3600 * 10; // 默认10小时
public const string JwtIssuer = "yilian";
public const string JwtAudience = "yilian";
public const string JwtSecretKey = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrkzI1NiJ9eyJjbGFTT";
public const string JwtUserToken = "###jwt###";
/// <summary>
/// 创建jwt令牌
/// </summary>
public static string CreateJwtToken(ClaimsIdentity identity)
{
var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(JwtSecretKey));
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(identity),
Expires = DateTime.UtcNow.AddSeconds(ExpireInSeconds),
Issuer = JwtIssuer,
Audience = JwtAudience,
SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
public static string CreateJwtToken2(ClaimsIdentity identity)
{
var key = new SymmetricSecurityKey(Convert.FromBase64String(JwtSecretKey));
// 添加 JTI (JWT ID) 用于黑名单机制
var claims = new ClaimsIdentity(identity);
if (!claims.HasClaim(c => c.Type == "jti"))
{
claims.AddClaim(new Claim("jti", Guid.NewGuid().ToString("N")));
}
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = claims,
Expires = DateTime.UtcNow.AddSeconds(ExpireInSeconds),
IssuedAt = DateTime.Now,
Issuer = JwtIssuer,
Audience = JwtAudience,
SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha512)
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
/// <summary>
/// 解析JWT token
/// </summary>
/// <param name="token">JWT token字符串</param>
/// <returns>解析后的JWT token对象</returns>
public static JwtSecurityToken ParseJwtToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
return tokenHandler.ReadJwtToken(token);
}
/// <summary>
/// 检查token是否需要续期
/// </summary>
/// <param name="token">JWT token对象</param>
/// <param name="thresholdSeconds">续期阈值(秒)</param>
/// <returns>是否需要续期</returns>
public static bool NeedRefreshToken(JwtSecurityToken token, int thresholdSeconds = 3600)
{
var timeUntilExpiry = token.ValidTo - DateTime.UtcNow;
return timeUntilExpiry.TotalSeconds < thresholdSeconds;
}
}
}