Files
QYZH.InteractiveMagazine/QYZH.InteractiveMagazine.Infrastructure/Middleware/JwtAutoRefreshMiddleware.cs
glz 831f8ba7f5 feat: 初始化后台管理模块与基础业务框架
1.  新增依赖注入生命周期标记接口、基础仓储与管理员仓储实现
2.  新增管理员认证与用户服务接口,补充认证相关DTO
3.  重构实体审计字段命名,统一Created/UpdatedAt规范
4.  新增大量业务实体类与API版本枚举配置
5.  集成Autofac依赖注入、JWT自动刷新与跨域配置
6.  替换原有微信小程序与旧认证服务为后台管理系统架构
7.  完善Swagger文档配置与项目基础部署配置
2026-06-01 17:59:23 +08:00

80 lines
2.8 KiB
C#

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using QYZH.InteractiveMagazine.Infrastructure.Cache;
using QYZH.InteractiveMagazine.Models.Settings;
using System.IdentityModel.Tokens.Jwt;
namespace QYZH.InteractiveMagazine.Infrastructure.Middleware;
public class JwtAutoRefreshMiddleware
{
private readonly RequestDelegate _next;
private readonly IConfiguration _configuration;
private const string TokenKeyPrefix = "InteractiveMagazine:AdminAuth:Token";
private const int RefreshThresholdMinutes = 10;
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 TryAutoRefreshTokenAsync(context, token);
}
await _next(context);
}
private async Task TryAutoRefreshTokenAsync(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;
if (remainingTime <= TimeSpan.FromMinutes(RefreshThresholdMinutes) && remainingTime > TimeSpan.Zero)
{
var userId = jwtToken.Claims.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
var userName = jwtToken.Claims.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Name)?.Value;
if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(userName))
{
return;
}
var jwtSettings = _configuration.GetSection("JwtSettings").Get<JwtSettings>();
if (jwtSettings == null)
{
return;
}
var newToken = QYZH.InteractiveMagazine.Infrastructure.Auth.JwtHelper.GenerateToken(
long.Parse(userId), userName, jwtSettings);
await RedisHelper.StringSetAsync(
$"{TokenKeyPrefix}:{userId}",
newToken,
TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes));
context.Response.Headers["X-New-Token"] = newToken;
}
}
catch
{
// 忽略自动刷新异常,由后续认证中间件处理
}
}
}