Files
QYZH.InteractiveMagazine/QYZH.InteractiveMagazine.Infrastructure/Auth/JwtHelper.cs
glz bfdfad14d8 refactor(auth): 重构JWT认证相关代码,优化声明获取逻辑
1. 提取通用的GetClaim方法简化多声明类型查找逻辑
2. 重构JWT认证配置代码,拆分配置逻辑到单独方法
3. 优化开发环境下的认证策略,支持无认证和JWT认证自动切换
2026-07-02 08:52:41 +08:00

170 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.IdentityModel.Tokens;
using QYZH.InteractiveMagazine.Models.Settings;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace QYZH.InteractiveMagazine.Infrastructure.Auth;
/// <summary>
/// JWT工具类
/// </summary>
public static class JwtHelper
{
public const string AdminTokenKeyPrefix = "InteractiveMagazine:AdminAuth:Token";
public const string WeChatTokenKeyPrefix = "InteractiveMagazine:WeChatAuth:Token";
/// <summary>
/// 生成JWT令牌管理端 / 单用户场景)
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="userName">用户名</param>
/// <param name="settings">JWT配置</param>
/// <returns>JWT令牌字符串</returns>
public static string GenerateToken(long userId, string userName, JwtSettings settings)
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userId.ToString()),
new Claim(JwtRegisteredClaimNames.Name, userName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
new Claim(ClaimTypes.Name, userName)
};
return BuildToken(claims, settings);
}
/// <summary>
/// 生成JWT令牌小程序场景同时携带 WxUserId 和 UserId
/// </summary>
/// <param name="wxUserId">微信用户IDWxUser.Id</param>
/// <param name="userId">当前激活用户IDUsers.Id无用户时为 0</param>
/// <param name="userName">用户名</param>
/// <param name="settings">JWT配置</param>
/// <returns>JWT令牌字符串</returns>
public static string GenerateToken(long wxUserId, long userId, string userName, JwtSettings settings)
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userId.ToString()),
new Claim(JwtRegisteredClaimNames.Name, userName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
new Claim(ClaimTypes.Name, userName),
new Claim(WxUserIdClaimType, wxUserId.ToString())
};
return BuildToken(claims, settings);
}
/// <summary>
/// 自定义 Claim 类型WxUserId
/// </summary>
public const string WxUserIdClaimType = "WxUserId";
public static string BuildAdminTokenKey(string userId)
{
return $"{AdminTokenKeyPrefix}:{userId}";
}
public static string BuildWeChatTokenKey(string wxUserId, string userId)
{
return $"{WeChatTokenKeyPrefix}:{wxUserId}:{userId}";
}
public static string BuildWeChatTokenKey(long wxUserId, long userId)
{
return BuildWeChatTokenKey(wxUserId.ToString(), userId.ToString());
}
private static string BuildToken(Claim[] claims, JwtSettings settings)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(settings.SecretKey!));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: settings.Issuer,
audience: settings.Audience,
claims: claims,
expires: DateTime.Now.AddDays(settings.JwtTokenExpiryDays),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
/// <summary>
/// 获取Token过期时间
/// </summary>
/// <param name="token">JWT令牌</param>
/// <returns>过期时间</returns>
public static DateTime? GetTokenExpiry(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
if (tokenHandler.ReadToken(token) is JwtSecurityToken jwtToken)
{
return jwtToken.ValidTo;
}
return null;
}
/// <summary>
/// 从Token中获取用户ID
/// </summary>
/// <param name="token">JWT令牌</param>
/// <returns>用户ID</returns>
public static long? GetUserIdFromToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
if (tokenHandler.ReadToken(token) is JwtSecurityToken jwtToken)
{
var userIdClaim = GetClaim(jwtToken, ClaimTypes.NameIdentifier, JwtRegisteredClaimNames.NameId, JwtRegisteredClaimNames.Sub);
if (long.TryParse(userIdClaim?.Value, out long userId))
{
return userId;
}
}
return null;
}
/// <summary>
/// 从Token中获取微信用户IDWxUserId
/// </summary>
/// <param name="token">JWT令牌</param>
/// <returns>WxUserId</returns>
public static long? GetWxUserIdFromToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
if (tokenHandler.ReadToken(token) is JwtSecurityToken jwtToken)
{
var wxUserIdClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == WxUserIdClaimType);
if (long.TryParse(wxUserIdClaim?.Value, out long wxUserId))
{
return wxUserId;
}
}
return null;
}
/// <summary>
/// 从Token中获取用户名
/// </summary>
/// <param name="token">JWT令牌</param>
/// <returns>用户名</returns>
public static string GetUserNameFromToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
if (tokenHandler.ReadToken(token) is JwtSecurityToken jwtToken)
{
return GetClaim(jwtToken, ClaimTypes.Name, JwtRegisteredClaimNames.UniqueName, JwtRegisteredClaimNames.Name)?.Value ?? string.Empty;
}
return string.Empty;
}
private static Claim? GetClaim(JwtSecurityToken jwtToken, params string[] claimTypes)
{
return jwtToken.Claims.FirstOrDefault(c => claimTypes.Contains(c.Type));
}
}