如何在带[Authorize]的Asp.Net Web API控制器构造函数中注入用户身份
这个问题在ASP.NET Web API开发中太常见了——控制器构造函数执行时,请求上下文还没完全初始化,所以确实拿不到User.Identity的值。下面给你几个经过实践验证的最佳解决方案,按推荐程度排序:
方案1:依赖注入(DI)+ 自定义用户服务(最推荐)
这是最符合SOLID设计原则的方案,能彻底解耦控制器、Repository和用户上下文,还方便单元测试。步骤如下:
- 定义一个获取当前用户的接口,抽象用户信息的获取逻辑:
public interface ICurrentUserService { string GetUserName(); }
- 实现这个接口,利用Web API的请求上下文获取当前用户:
public class CurrentUserService : ICurrentUserService { private readonly HttpRequestMessage _request; public CurrentUserService(HttpRequestMessage request) { _request = request; } public string GetUserName() { var identity = _request?.Context?.User?.Identity; return identity?.IsAuthenticated == true ? identity.Name : null; } }
- 修改Repository,让它依赖
ICurrentUserService而非直接接收用户名:
public class Repository { private readonly string _userName; public Repository(ICurrentUserService currentUserService) { _userName = currentUserService.GetUserName(); } // 你的Repository业务方法 }
- 注册依赖注入(以Web API常用的Autofac容器为例,其他容器配置逻辑类似):
在WebApiConfig.cs中完成容器注册:
var builder = new ContainerBuilder(); builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); builder.RegisterType<CurrentUserService>().As<ICurrentUserService>().InstancePerRequest(); builder.RegisterType<Repository>().InstancePerRequest(); var container = builder.Build(); config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
- 最后修改控制器,通过构造函数注入Repository:
[Authorize] public class HomeController : ApiController { private readonly Repository _repo; public HomeController(Repository repo) { _repo = repo; } // 你的API动作方法,直接使用_repo即可 }
方案2:重写ApiController的Initialize方法
你提到Initialize方法拿不到用户信息?其实是可以的——Initialize方法在构造函数执行后、请求上下文完全初始化完成后触发。试试这个写法:
[Authorize] public class HomeController : ApiController { private Repository _repo; protected override void Initialize(HttpControllerContext controllerContext) { base.Initialize(controllerContext); var userName = User.Identity.IsAuthenticated ? User.Identity.Name : null; _repo = new Repository(userName); } // API方法中直接使用_repo }
这个方案实现简单,但缺点是控制器和Repository耦合度高,不利于单元测试,适合小型项目或快速验证场景。
方案3:使用动作过滤器注入Repository
如果不想引入DI容器,也可以用动作过滤器在每个API方法执行前初始化Repository:
- 给控制器添加Repository属性:
[Authorize] public class HomeController : ApiController { public Repository Repo { get; set; } // API动作方法 }
- 自定义动作过滤器:
public class RepositoryInjectFilter : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { var controller = actionContext.ControllerContext.Controller as HomeController; if (controller != null) { var principal = actionContext.ControllerContext.RequestContext.Principal; var userName = principal?.Identity?.IsAuthenticated == true ? principal.Identity.Name : null; controller.Repo = new Repository(userName); } base.OnActionExecuting(actionContext); } }
- 给控制器添加过滤器特性:
[Authorize] [RepositoryInjectFilter] public class HomeController : ApiController { // ... }
这个方案也能解决问题,但同样存在耦合度高的问题,适合快速实现的场景。
内容的提问来源于stack exchange,提问作者Tejas Patel
相关产品推荐
相关产品推荐

