ASP.NET Core 3.1 基于ASP.NET Identity的Web应用部署后频繁要求用户重登怎么解决
问题核心原因确认
该现象确实和应用程序池回收直接相关,但核心触发机制和你之前的判断有偏差:
你认为认证信息完全存在客户端Cookie中、和服务端无关,但实际上ASP.NET Identity生成的认证Cookie并非明文存储的用户数据,而是经过服务端Data Protection系统加密、签名的载荷。服务端每次验证Cookie时,必须使用和加密时完全一致的密钥才能解密通过。
而ASP.NET Core 3.1默认的Data Protection密钥存储逻辑存在适配托管环境的问题:
- 无显式配置时,默认密钥会存储在应用内容根目录下的
keys文件夹,且部分托管环境会在应用池回收、站点重启时清空该临时目录,或是为每个应用实例分配隔离的临时存储。 - 应用池回收后新生成的应用实例会重新生成一套全新的密钥,旧实例加密的Cookie无法被新密钥解密,直接触发强制登出。本地运行时因为目录存储稳定、无清空逻辑,所以不会出现该问题。
无权修改应用池配置的解决方案
核心思路是显式配置Data Protection密钥的持久化存储位置,让密钥存储在不受应用池回收影响的介质中,推荐两种适配你现有架构的实现方式:
方案1:将密钥持久化到现有MySQL数据库(推荐)
复用你已经在用的ApplicationDbContext存储密钥,无需额外维护存储介质,操作如下:
- 先引入对应Nuget包:
Microsoft.AspNetCore.DataProtection.EntityFrameworkCore - 在
ConfigureServices方法的AddDbContext配置之后,添加Data Protection的配置:
services.AddDataProtection() // 将密钥持久化到现有MySQL数据库 .PersistKeysToDbContext<ApplicationDbContext>() // 设置唯一的应用标识,避免同服务器其他应用的密钥冲突 .SetApplicationName("你的应用唯一标识");
首次运行时会自动在数据库中创建DataProtectionKeys表存储密钥,后续无论应用池如何回收,只要数据库连接正常,都能复用原有密钥解密Cookie。
方案2:将密钥存储到托管环境提供的固定持久化路径
如果托管环境提供了不会被回收、不会被部署覆盖的固定文件目录,可以直接将密钥存储到该路径:
// 从配置文件读取托管环境提供的持久化存储路径 var persistentKeyPath = Configuration["PersistentKeyStoragePath"]; services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(persistentKeyPath)) .SetApplicationName("你的应用唯一标识");
注意:不要将路径设置为应用部署目录下的子文件夹,大部分托管环境会在重新部署、应用池回收时清空部署目录内容。
配置后仍频繁登出的其他排查方向
如果完成上述配置后问题依然存在,可排查以下诱因:
- Cookie安全策略配置缺失:生产环境为HTTPS时,需在
ConfigureApplicationCookie配置中补充options.Cookie.SecurePolicy = CookieSecurePolicy.Always;,避免Cookie在HTTPS传输中被拦截或丢弃。 - Cookie同意策略影响:你的配置中
CheckConsentNeeded = context => true;,如果用户未勾选Cookie同意选项,Cookie将不会被持久化,每次关闭浏览器后就会登出。可根据业务需求调整该逻辑,或是在页面上明确引导用户勾选同意。 - 多实例负载均衡场景:如果托管环境部署了多个应用实例做负载均衡,默认每个实例会生成独立密钥,请求路由到不同实例时会触发登出,此时必须配置统一的共享密钥存储(即上述两种方案)才能解决。
内容的提问来源于stack exchange,提问作者Mike Pearce
相关产品推荐
相关产品推荐

