如何在 Web API .NET Core 的控制器之外获取当前用户
Posted
技术标签:
【中文标题】如何在 Web API .NET Core 的控制器之外获取当前用户【英文标题】:How to get current User outside a Controller in Web API .NET Core 【发布时间】:2017-06-11 01:06:42 【问题描述】:我正在尝试从我的 Web API 中的控制器外部的上下文中获取当前用户。我正在使用 OpenIddict 对用户进行身份验证,因此授权是通过令牌进行的。
我已在我的 Startup.cs 中将 HttpContextAcessor 注册为单例:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
之后,我将 HttpContexrAcessor 注入到我的集线器中,如下所示:
public class NotificationHub : Hub
private IHttpContextAccessor _contextAccessor;
private HttpContext _context get return _contextAccessor.HttpContext;
public NotificationHub(IHttpContextAccessor contextAccessor)
_contextAccessor = contextAccessor;
public async Task JoinGroup()
Groups.Add(Context.ConnectionId, $"notification__context.User.Identity.Name");
public void Send(JsonResult notification)
Clients.Client(Context.ConnectionId).sendNotification(notification);
问题在于 _context.User.Identity.Name 始终为空。
有没有办法做到这一点?
【问题讨论】:
在请求管道之外访问 HttpContext 是灾难的根源。如果你的班级需要User.Identity.Name
,那么用传入的数据构造它。如果您在构建类时无法访问 User.Identity.Name
之类的内容,那么无论如何您都不太可能访问类中的静态 HttpContext
。
@ChrisPratt 问题是我需要将用户映射到集线器的 ConnectionID 或将用户插入集线器的组中,其中用户将是唯一的成员。在通知的情况下,它将使用 HubContext 从控制器发送,因此我只需将其发送给一个用户。
如果你从控制器发送它,那么你有机会在那个时候传递用户。与存在的活动用户进行交互更合适。如果您的设置不适合这样做,那就是设计问题。
@ChrisPratt 是的,但是无法从控制器获取集线器 ConnectionID,因此我无法通过 ConnectionID 发送通知,也无法将用户插入组中,因为它还需要 connectionid完成。
再次,设计问题。然后,应该将“Hub ConnectionID”注入到任何需要它的类中。换句话说,你很可能在一个班级中混为一谈。记住 SOLID,类应该封装离散的功能单元(做一件事,并且做好)。需要并非同时可用的依赖项表明您的课程在这方面失败了。
【参考方案1】:
在我使用 .Net Core 2.0 的情况下,我需要在应用程序服务中获取控制器外部的用户 ID,我执行了以下操作:
在 Startup.cs 我在 ConfigureServices
下添加了这一行services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
我创建了以下类
public class UserResolverService
private readonly IHttpContextAccessor _httpContext;
private readonly UserManager<ApplicationUser> _userManager;
public UserResolverService(IHttpContextAccessor httpContext, UserManager<ApplicationUser> userManager)
_httpContext = httpContext;
_userManager = userManager;
public string GetUserId()
var userId = _userManager.GetUserId(_httpContext.HttpContext.User);
return userId;
在我的 Application Service 类中,我调用了 UserResolverService
public class MyApplicationService
private readonly ApplicationDbContext _context;
private readonly UserResolverService _userResolverService;
public MyApplicationService(ApplicationDbContext context, UserResolverService userResolverService)
_context = context;
_userResolverService = userResolverService;
public async Task Create(MyModel entity)
entity.CreatorUserId = _userResolverService.GetUserId();
_context.MyModel.Add(entity);
await _context.SaveChangesAsync();
另外,如果您不想使用 UserManager,您可以像这样简单地创建 UserResolverService 类:
public class UserResolverService
private readonly IHttpContextAccessor _httpContext;
public UserResolverService(IHttpContextAccessor httpContext)
_httpContext = httpContext;
public string GetUserId()
var user = _httpContext?.HttpContext?.User as ClaimsPrincipal;
var userId = user.Claims.ElementAt(0).Value;
return userId;
【讨论】:
【参考方案2】:试试这个:https://msdn.microsoft.com/pt-br/library/system.threading.thread.currentprincipal(v=vs.110).aspx
System.Threading.Thread.CurrentPrincipal
【讨论】:
这不仅可以被任何 3rd 方库更改(因为它是可变的),它也可能不会在任何异步调用之后设置。相当危险。【参考方案3】:尝试从您的启动中删除此行:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
我相信框架已经为你注册了。
【讨论】:
【参考方案4】:试试这个:
HttpContext.Current.User.Identity.Name
【讨论】:
这绝对不是答案。以上是关于如何在 Web API .NET Core 的控制器之外获取当前用户的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Web API 控制器添加到现有的 ASP.NET Core MVC?
如何在 ASP.NET Core Web API 中使用 MassTransit 事件总线?