为何基类BaseApiController的ActiveUser属性值会异常?
问题原因及修复方案
核心问题:静态字段的线程安全隐患
你的BaseApiController中CurrentUser被声明为静态字段(public static User),静态成员属于类级别,所有控制器实例共享同一个CurrentUser对象。
在ASP.NET Web API的多请求并发场景下:
- 数千用户的请求会同时被服务器处理,多个控制器实例(或同一控制器的不同请求实例)会同时修改这个静态字段。
- 当请求A刚把
CurrentUser设为用户X,请求B紧接着把它覆盖为用户Y,此时请求A后续操作读取ActiveUser.Id时,就会拿到用户Y的ID,导致日志错误关联用户。
修复方案
方案1:将静态字段改为实例字段
去掉CurrentUser的static修饰符,让每个控制器实例持有自己的用户信息:
public class BaseApiController : ApiController { public User CurrentUser; // 移除static关键字 public BaseApiController() { } protected override void Initialize(HttpControllerContext controllerContext) { base.Initialize(controllerContext); var request = controllerContext.Request; if (request.Headers.Authorization != null && request.Headers.Authorization.Scheme.Equals("bearer", StringComparison.OrdinalIgnoreCase)) { CurrentUser = Helpers.JwtAuthentication.UserToken(request.Headers.Authorization.Parameter); } } protected User ActiveUser { get { return CurrentUser; } } }
方案2:直接在属性中获取用户信息(无需字段存储)
如果JWT解析性能开销不大,也可以直接在ActiveUser属性中解析当前请求的用户,避免字段存储:
public class BaseApiController : ApiController { protected override void Initialize(HttpControllerContext controllerContext) { base.Initialize(controllerContext); } protected User ActiveUser { get { var request = ControllerContext.Request; if (request.Headers.Authorization != null && request.Headers.Authorization.Scheme.Equals("bearer", StringComparison.OrdinalIgnoreCase)) { return Helpers.JwtAuthentication.UserToken(request.Headers.Authorization.Parameter); } return null; } } }
额外建议:使用HttpContext.Items存储请求级数据
如果需要在请求的多个环节共享用户信息,还可以将解析后的用户对象存入HttpContext.Items,这是请求级别的存储容器,天然和当前请求绑定,不会出现线程安全问题:
protected override void Initialize(HttpControllerContext controllerContext) { base.Initialize(controllerContext); var request = controllerContext.Request; if (request.Headers.Authorization != null && request.Headers.Authorization.Scheme.Equals("bearer", StringComparison.OrdinalIgnoreCase)) { var user = Helpers.JwtAuthentication.UserToken(request.Headers.Authorization.Parameter); controllerContext.Request.Properties["CurrentUser"] = user; } } protected User ActiveUser { get { ControllerContext.Request.Properties.TryGetValue("CurrentUser", out var user); return user as User; } }
内容的提问来源于stack exchange,提问作者mitchsnitchel
相关产品推荐
相关产品推荐

