ASP.NET Core项目JWT滑动过期实现方案与部署位置选型咨询
JWT滑动过期实现方案及部署位置建议
最佳实现方式
你提到的「校验合法JWT后按需重新签发、通过响应头返回供客户端更新本地令牌」是目前JWT滑动过期的标准最佳实践,该方案和原Cookie滑动过期的逻辑对齐,用户无感知,迁移成本最低。
逻辑部署位置选择
最优部署位置是自定义JWT身份验证逻辑/官方JwtBearer的事件回调,而非AuthorizationFilter,原因如下:
- 执行顺序更靠前:身份验证中间件属于ASP.NET Core管道的前置环节,早于MVC路由匹配、授权过滤器执行,所有携带JWT的请求(包括静态资源、自定义端点等非MVC接口请求)都能被统一处理,不会出现逻辑遗漏
- 符合职责边界:身份验证中间件的核心职责就是令牌校验、构造身份凭证,重发新令牌属于身份验证流程的延伸逻辑,放在此处符合单一职责原则,后续维护成本更低
- 复用性更强:如果后续项目扩展API、Blazor等其他接入方式,中间件逻辑可以直接复用,不需要为不同路由体系单独适配过滤器
具体实现步骤
推荐直接复用官方JwtBearer中间件的OnTokenValidated事件实现,不需要完全重写自定义身份验证中间件,稳定性更高:
- 首先配置基础JWT校验规则,设置合理的过期缓冲时间和令牌有效期,示例配置如下:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = "自定义Issuer", ValidateAudience = true, ValidAudience = "自定义Audience", ValidateLifetime = true, ClockSkew = TimeSpan.FromMinutes(5), // 令牌过期后的缓冲有效期,可按需调整 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的签名密钥")) }; options.Events = new JwtBearerEvents { OnTokenValidated = async context => { // 从已校验通过的身份信息中获取原令牌的过期时间 var expClaim = context.Principal.FindFirst(ClaimTypes.Expiration)?.Value; if (long.TryParse(expClaim, out long expUnixTime)) { var expireTime = DateTimeOffset.FromUnixTimeSeconds(expUnixTime).UtcDateTime; var now = DateTime.UtcNow; // 自定义触发重签的条件:例:剩余有效期不足3分钟时触发重签 if (expireTime - now < TimeSpan.FromMinutes(3)) { // 复用原令牌的Claims生成新令牌,和登录接口的签发逻辑保持一致 var newToken = GenerateJwtToken(context.Principal.Claims); // 写入自定义响应头返回给客户端 context.Response.Headers["X-New-Jwt-Token"] = newToken; } } await Task.CompletedTask; } }; });
- 客户端适配:每次请求完成后检查响应头是否存在
X-New-Jwt-Token,如果存在则替换本地存储的旧JWT,后续请求携带新令牌即可。
补充注意事项
- 如果需要支持令牌撤销能力,可以搭配短有效期JWT+长有效期RefreshToken的方案,重签逻辑中额外校验RefreshToken的有效性,避免令牌被盗用后被持续重签
- 不要在AuthorizationFilter中实现该逻辑的另一个原因是:过滤器仅会作用于标注了
[Authorize]的控制器/动作,匿名接口携带JWT的场景会被漏掉,无法统一处理滑动过期逻辑
内容的提问来源于stack exchange,提问作者user3132295
相关产品推荐
相关产品推荐

