using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using QYZH.InteractiveMagazine.Infrastructure.Auth;
using QYZH.InteractiveMagazine.Models.Settings;
using System.IdentityModel.Tokens.Jwt;
namespace QYZH.InteractiveMagazine.Infrastructure.Middleware;
///
/// JWT 自动刷新中间件
/// 功能:
/// 每次请求都刷新 Redis 中 Token 的过期时间(保持会话活跃)
/// 前端永远使用同一个 Token,无需处理 Token 刷新
///
public class JwtAutoRefreshMiddleware
{
private readonly RequestDelegate _next;
private readonly IConfiguration _configuration;
private const string AdminTokenKeyPrefix = "InteractiveMagazine:AdminAuth:Token";
private const string WeChatTokenKeyPrefix = "InteractiveMagazine:WeChatAuth:Token";
public JwtAutoRefreshMiddleware(RequestDelegate next, IConfiguration configuration)
{
_next = next;
_configuration = configuration;
}
public async Task InvokeAsync(HttpContext context)
{
var authHeader = context.Request.Headers.Authorization.FirstOrDefault();
if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer "))
{
var token = authHeader.Substring("Bearer ".Length).Trim();
await TryRefreshRedisTokenExpiryAsync(context, token);
}
await _next(context);
}
private async Task TryRefreshRedisTokenExpiryAsync(HttpContext context, string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
if (tokenHandler.ReadToken(token) is not JwtSecurityToken jwtToken)
{
return;
}
var expiryTime = jwtToken.ValidTo;
var remainingTime = expiryTime - DateTime.Now;
// JWT 已过期,不处理
if (remainingTime <= TimeSpan.Zero)
{
return;
}
var userId = jwtToken.Claims.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(userId))
{
return;
}
var wxUserId = jwtToken.Claims.FirstOrDefault(c => c.Type == JwtHelper.WxUserIdClaimType)?.Value;
if (string.IsNullOrEmpty(wxUserId))
{
return;
}
var jwtSettings = _configuration.GetSection("JwtSettings").Get();
if (jwtSettings == null || jwtSettings.ExpiryMinutes <= 0)
{
return;
}
// 每次请求都刷新 Redis 中 Token 的过期时间
await RefreshRedisTokenExpiryAsync(wxUserId,userId, token, jwtSettings.ExpiryMinutes);
}
catch
{
// 忽略自动刷新异常,由后续认证中间件处理
}
}
///
/// 刷新 Redis 中已存在 Token 的过期时间(保持会话活跃)
///
private async Task RefreshRedisTokenExpiryAsync(string wxUserId,string userId, string currentToken, int expiryMinutes)
{
// 检查 Admin Token
var adminTokenKey = $"{AdminTokenKeyPrefix}:{userId}";
var adminToken = await RedisHelper.GetAsync(adminTokenKey);
if (!string.IsNullOrEmpty(adminToken))
{
await RedisHelper.SetAsync(adminTokenKey, currentToken, TimeSpan.FromMinutes(expiryMinutes));
return;
}
// 检查 WeChat Token
var wechatTokenKey = $"{WeChatTokenKeyPrefix}:{wxUserId}{userId}";
var wechatToken = await RedisHelper.GetAsync(wechatTokenKey);
if (!string.IsNullOrEmpty(wechatToken))
{
await RedisHelper.SetAsync(wechatTokenKey, currentToken, TimeSpan.FromMinutes(expiryMinutes));
}
}
}