.NET Core 3.1应用登出后旧Cookie仍可访问API的解决需求
我在.NET Core 3.1应用中遇到如下场景:用户登录后从本地存储获取Cookie,执行登出操作后,使用该Cookie通过Postman仍能访问API,需要阻止这种情况发生。
当前Startup配置代码
options.Events = new CookieAuthenticationEvents { OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync };
当前登出逻辑代码
var authenticationName = HttpContext.User?.Identity?.Name; var user = await userManager.FindByNameAsync(authenticationName); if (user != null) { await userManager.UpdateSecurityStampAsync(user); await userManager.UpdateAsync(user); } await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme)
修复方案
1. 调整SecurityStamp验证间隔
SecurityStampValidator.ValidatePrincipalAsync默认30分钟才会验证一次SecurityStamp,导致登出后更新了Stamp,旧Cookie仍能在30分钟内正常访问。可以缩短验证间隔,确保Stamp变更后快速生效:
在Startup中添加配置:
services.Configure<SecurityStampValidatorOptions>(options => { // 设置为10秒验证一次,可根据业务需求调整 options.ValidationInterval = TimeSpan.FromSeconds(10); });
2. 确保登出时彻底清除Cookie
SignOutAsync理论上会清除认证Cookie,但部分场景下可能因配置异常失效,可以手动强制删除Cookie:
// 执行登出操作 await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); // 手动删除Cookie确保彻底清除 Response.Cookies.Delete(CookieAuthenticationDefaults.CookiePrefix + CookieAuthenticationDefaults.AuthenticationScheme);
3. 移除冗余的UpdateAsync调用
UpdateSecurityStampAsync方法内部已经会调用UpdateAsync更新用户数据,登出代码里的await userManager.UpdateAsync(user);属于冗余操作,直接删除即可,优化后代码:
var authenticationName = HttpContext.User?.Identity?.Name; var user = await userManager.FindByNameAsync(authenticationName); if (user != null) { await userManager.UpdateSecurityStampAsync(user); } await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
4. 强制每次请求验证Principal(可选)
如果需要更高的安全性,可以自定义OnValidatePrincipal事件,强制每次请求都验证SecurityStamp:
options.Events.OnValidatePrincipal = async context => { var userManager = context.HttpContext.RequestServices.GetRequiredService<IUserManager<IdentityUser>>(); var user = await userManager.GetUserAsync(context.Principal); if (user != null) { var isValid = await userManager.VerifyUserTokenAsync( user, TokenOptions.DefaultProvider, "SecurityStamp", context.Properties.GetTokenValue("SecurityStamp")); if (!isValid) { context.RejectPrincipal(); await context.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); } } };
内容的提问来源于stack exchange,提问作者Omar Ahmed
相关产品推荐
相关产品推荐

