如何在 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&lt;IHttpContextAccessor, HttpContextAccessor&gt;();

我相信框架已经为你注册了。

【讨论】:

【参考方案4】:

试试这个:

HttpContext.Current.User.Identity.Name

【讨论】:

这绝对不是答案。

以上是关于如何在 Web API .NET Core 的控制器之外获取当前用户的主要内容,如果未能解决你的问题,请参考以下文章

如何在 .NET Core Web API 中配置并发?

如何将 Web API 控制器添加到现有的 ASP.NET Core MVC?

.NET Core Web APi类库如何内嵌运行?

如何在 ASP.NET Core Web API 中使用 MassTransit 事件总线?

如何从 ASP.NET MVC 到 ASP.NET Core Web API 的 PUT?

如何在 ASP.NET Core Web API 中添加两个不同的令牌