You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HttpContextAccessor是否存在缓存或线程安全问题?用户身份Claims混乱问题原因咨询

HttpContextAccessor是否存在缓存或线程安全问题?用户身份Claims混乱问题原因咨询

这问题我之前也碰到过,核心原因不是HttpContextAccessor的线程安全问题,而是服务生命周期不匹配导致的Scoped服务被意外提升为Singleton,进而引发了跨请求的状态污染。

先理清你的服务生命周期逻辑

  • 你注册的 IJwtService 是 Scoped 生命周期,正常情况下每个HTTP请求都会创建一个独立的实例,和请求绑定。
  • 但你的 AccessCheckToRoutesMiddleware 是ASP.NET Core中间件,中间件默认是 Singleton 生命周期——它在应用启动时就被初始化,整个应用运行期间只有这一个实例。

为什么会出现Claims混乱?

当Singleton的中间件直接依赖Scoped的JwtService时,ASP.NET Core的DI容器会被迫把JwtService的生命周期提升为Singleton(因为Singleton服务不能依赖比它生命周期短的服务,否则会导致短生命周期服务被长期持有)。

这就意味着整个应用里只有一个JwtService实例,所有请求共用它。你之前在构造函数或者_getIdentity方法里缓存了_identity变量:

  • 第一个请求进来时,会把当前用户的Identity存入_identity;
  • 后续请求进来时,因为_identity已经不为空,就直接复用这个值,自然就拿到了前一个用户的Claims,出现混乱。

为什么改成每次直接获取就正常?

IHttpContextAccessor本身是Singleton,但它内部用AsyncLocal<T>来存储HttpContext——这个特性能保证在异步流程中,每个请求上下文都能拿到属于自己的HttpContext。

你每次调用httpContextAccessor.HttpContext.User.Identity时,拿到的都是当前请求的正确Identity,没有了跨请求的缓存,自然就不会出现Claims混淆的问题。

给你一个根本的解决方案

要避免这种问题,不要在中间件的构造函数里注入Scoped服务,而是在中间件的InvokeAsync方法中注入(ASP.NET Core允许在Invoke方法里注入Scoped服务,因为Invoke是每个请求执行一次):

public class AccessCheckToRoutesMiddleware
{
    private readonly RequestDelegate _next;

    public AccessCheckToRoutesMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // 在InvokeAsync里注入Scoped的IJwtService,每个请求都会拿到新的实例
    public async Task InvokeAsync(HttpContext context, IJwtService jwtService)
    {
        if (jwtService.IsPrivilegedUser())
        {
            // 你的权限校验逻辑
        }
        await _next(context);
    }
}

这样每个请求都会使用独立的JwtService实例,彻底避免跨请求的状态污染。

备注:内容来源于stack exchange,提问作者Rajeev Menon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 07:10:28