ASP.NET Core中如何实现JWT过期时同步删除对应HTTPOnly Cookie
问题根因
当前写入Cookie时未配置和JWT匹配的过期属性,默认生成的是会话级Cookie,仅在浏览器关闭时清除,和JWT自身的有效期完全独立,因此会出现JWT已过期但Cookie仍被浏览器携带发送的问题。
具体实现方案
1. 写入Cookie时同步对齐JWT过期时间(核心方案)
生成JWT时明确记录令牌的绝对过期时间,写入Cookie时将该时间赋值给CookieOptions.Expires属性,浏览器会在到期时自动清除Cookie,从根源避免过期令牌被发送到服务端。
注意:你已经将
ClockSkew设置为TimeSpan.Zero,无需额外预留时间缓冲,两边时间完全对齐即可。
修改登录逻辑的代码参考:
// 生成JWT时提前定义统一的过期时间,例:有效期2小时 DateTimeOffset jwtExpireTime = DateTimeOffset.UtcNow.AddHours(2); // 你的原有JWT生成逻辑,将jwtExpireTime写入JWT的exp声明 string generatedToken = BuildJwtToken( issuer: Configuration["Jwt:Issuer"], audience: Configuration["Jwt:Issuer"], signingKey: Configuration["Jwt:Key"], expires: jwtExpireTime ); // 写入Cookie时同步设置完全一致的过期时间 Response.Cookies.Append("X-Access-Token", generatedToken, new CookieOptions() { HttpOnly = true, SameSite = SameSiteMode.Strict, Secure = true, Expires = jwtExpireTime // 关键配置:和JWT有效期完全对齐 });
2. 鉴权失败时主动删除无效Cookie(兜底方案)
针对本地时间偏差、令牌被篡改、令牌被提前吊销等边界场景,可在JWT鉴权失败的回调中主动清除无效Cookie,避免浏览器反复携带无效令牌发起请求。
修改Startup中JwtBearer的事件配置:
options.Events = new JwtBearerEvents { OnMessageReceived = context => { if (context.Request.Cookies.ContainsKey("X-Access-Token")) { context.Token = context.Request.Cookies["X-Access-Token"]; } return Task.CompletedTask; }, // 鉴权失败回调:识别到无效/过期JWT时立即删除对应Cookie OnAuthenticationFailed = context => { // 仅在令牌过期、签名无效这类明确无效的场景下删除Cookie if (context.Exception is SecurityTokenExpiredException || context.Exception is SecurityTokenInvalidSignatureException || context.Exception is SecurityTokenInvalidIssuerException) { // 删除Cookie时必须和写入时的HttpOnly、SameSite、Secure、Domain、Path属性完全一致,否则会删除失败 context.Response.Cookies.Delete("X-Access-Token", new CookieOptions { HttpOnly = true, SameSite = SameSiteMode.Strict, Secure = true }); } return Task.CompletedTask; } };
配置注意事项
- 你当前代码中调用的
.AddCookie()是Cookie身份认证方案的配置,和你手动写入X-Access-Token、用JwtBearer读取Cookie校验的逻辑没有关联,该段配置不会作用于你自定义的JWT Cookie,不要混淆两套认证体系的逻辑。 - 如果需要实现滑动过期,可在请求经过鉴权后判断JWT剩余有效期,当有效期小于阈值(比如剩余不到30分钟)时生成新JWT,并重写Cookie更新过期时间即可。
内容的提问来源于stack exchange,提问作者kajahun123
相关产品推荐
相关产品推荐

