ASP.NET Core 5.0 Razor Pages应用Identity框架并发登录用户识别异常
问题排查与解决
根因说明
你的问题本质是请求级的用户上下文被存储到了全局共享的对象中,并发请求时不同用户的上下文互相覆盖,就会出现串号现象;而单用户刷新页面时没有并发冲突,上下文读取正确,所以展示恢复正常。ASP.NET Core Identity 本身的默认实现完全支持多用户并发登录,不存在开箱即用的串号问题。
具体排查步骤
1. 优先检查你封装的两个身份工具类
这是最高概率的问题来源:
- 如果工具类是静态类,且内部用静态字段/属性存储了
ClaimsPrincipal User、User实体、SignInManager、UserManager这类和请求关联的对象,立刻移除所有相关静态存储。静态类的静态成员是全应用全局共享的,并发请求会同时修改同一个静态变量,必然出现互相覆盖的问题。
解决方案:将静态工具类改为普通类,通过依赖注入注入到需要使用的PageModel或服务中,每次请求获取新的实例。 - 如果工具类是注入服务,确认服务注册的生命周期为Scoped,即注册代码为:
绝对不能使用services.AddScoped<I你的工具类接口, 你的工具类实现>(); // 无接口的情况用以下写法 services.AddScoped<你的工具类>();AddSingleton注册和请求上下文相关的服务,Singleton服务会在整个应用生命周期内只创建一个实例,所有请求共享,存储在成员变量中的用户上下文会被并发请求覆盖。
2. 检查PageModel及基类代码
检查所有Razor Pages PageModel,尤其是公共基类,有没有定义静态字段/属性存储当前用户信息,例如以下就是错误实现:
// 错误示例:静态变量全局共享,会被所有请求修改 public static User CurrentLoginUser { get; set; }
所有当前请求的用户信息,都应该每次使用时实时从User属性、UserManager.GetUserAsync(User)读取,不要缓存到静态变量中。
3. 检查Identity及DbContext的注册配置
确认你没有手动修改Identity相关服务、自定义MyDbContext的生命周期为Singleton:
- 默认
AddIdentity/AddDefaultIdentity注册的UserManager、SignInManager都是Scoped生命周期,不要手动更改。 - 默认
AddDbContext注册的MyDbContext是Scoped生命周期,如果你手动指定了ServiceLifetime.Singleton,请改回默认或显式指定ServiceLifetime.Scoped。
4. 检查IHttpContextAccessor的使用
如果你在服务中使用了IHttpContextAccessor获取当前用户,不要将HttpContext.User存储到单例服务的成员变量中,每次需要使用时实时读取:
// 正确示例:每次实时读取当前请求的用户 var userId = _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier); // 错误示例:单例服务中存储上下文会全局共享 private readonly ClaimsPrincipal _currentUser; public 你的服务(IHttpContextAccessor accessor) { _currentUser = accessor.HttpContext.User; // 构造函数中读取的是第一次实例化时的用户,后续所有请求都用这个值 }
内容的提问来源于stack exchange,提问作者bairog
相关产品推荐
相关产品推荐

