如何获得asp.net核心的当前用户

Meh*_*izi 100 c# asp.net-identity asp.net-core

我想让当前用户获取用户的信息,例如电子邮件.但我不能在asp.net核心中这样做.我很困惑这是我的代码.

HttpContext在控制器的构造函数中几乎为null .在每个动作中获得用户并不好.我想获得用户的信息并将其设置为ViewData;

public DashboardController()
{
    var user = HttpContext.User.GetUserId();
}
Run Code Online (Sandbox Code Playgroud)

ade*_*lin 127

User.FindFirst(ClaimTypes.NameIdentifier).Value
Run Code Online (Sandbox Code Playgroud)

编辑构造函数

下面代码有效:

public Controller(IHttpContextAccessor httpContextAccessor)
{
    var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value 
}
Run Code Online (Sandbox Code Playgroud)

编辑RTM

你应该注册IHttpContextAccessor:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }
Run Code Online (Sandbox Code Playgroud)

  • `ClaimTypes.NameIdentifier` 给出当前用户 id,`ClaimTypes.Name` 给出用户名。 (6认同)
  • 它适用于动作。但我想在控制器的构造函数中使用。 (3认同)
  • @ademcaglin 出于某些原因,用户在我的情况下返回 `null`?不过,我使用的是`.Net core 2.1 Web api`。 (3认同)
  • 有可能在课堂上使用它吗? (2认同)
  • 有人可以告诉我UserPrincipal.Current.Name怎么了吗? (2认同)

Ahm*_*mad 43

简单的方式,我检查.

private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

var user = await _userManager.GetUserAsync(HttpContext.User);
Run Code Online (Sandbox Code Playgroud)

那么你可以将这个变量的所有属性都像user.Email.我希望这会对某人有所帮助.

  • 在ASP.NET Core身份中,用户管理器是依赖注入提供的用于创建用户的服务。有关更多信息,请参见[docs](https://docs.microsoft.com/zh-cn/aspnet/core/security/authentication/identity?view=aspnetcore-2.1&amp;tabs=visual-studio%2Caspnetcore2x): (5认同)
  • 什么是_userManager? (2认同)
  • 如何在非异步方法中实现这一点? (2认同)

Hek*_*ryk 22

有另一种方法让当前用户进入Asp.NET Core - 我想我在这里看到了它,在SO ^^上

// Stores UserManager
private readonly UserManager<ApplicationUser> _manager; 

// Inject UserManager using dependency injection.
// Works only if you choose "Individual user accounts" during project creation.
public DemoController(UserManager<ApplicationUser> manager)  
{  
    _manager = manager;  
}

// You can also just take part after return and use it in async methods.
private async Task<ApplicationUser> GetCurrentUser()  
{  
    return await _manager.GetUserAsync(HttpContext.User);  
}  

// Generic demo method.
public async Task DemoMethod()  
{  
    var user = await GetCurrentUser(); 
    string userEmail = user.Email; // Here you gets user email 
    string userId = user.Id;
}  
Run Code Online (Sandbox Code Playgroud)

该代码转到名为DemoController的控制器.如果没有等待(将不会编译)将无法工作;)

  • 这需要使用身份 (3认同)

Gra*_*zer 15

截至目前(2017年4月),以下情况似乎如下:

public string LoggedInUser => User.Identity;
Run Code Online (Sandbox Code Playgroud)

至少在一个内部 Controller

  • 作为以前没有看过`=>`运算符的人,它被称为"表达体定义",在[本文档]中有描述(https://docs.microsoft.com/en-us/ DOTNET/CSHARP /语言参考/运营商/λ-操作者).以防万一像我这样的未来人想知道. (4认同)
  • 您不能将类型'System.Security.Principal.IIdentity'隐式转换为'string'. (3认同)
  • 字符串LoggedInUser = User.Identity.Name; (2认同)

Tom*_*kel 14

也许我没有看到答案,但这就是我的做法。

  1. .Net Core --> 属性 --> launchSettings.json

您需要更改这些值

"windowsAuthentication": true, // needs to be true
"anonymousAuthentication": false,  // needs to be false 
Run Code Online (Sandbox Code Playgroud)

Startup.cs --> ConfigureServices(...)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Run Code Online (Sandbox Code Playgroud)

MVC 或 Web Api 控制器

private readonly IHttpContextAccessor _httpContextAccessor;
//constructor then
_httpContextAccessor = httpContextAccessor;
Run Code Online (Sandbox Code Playgroud)

控制器方法:

string userName = _httpContextAccessor.HttpContext.User.Identity.Name;
Run Code Online (Sandbox Code Playgroud)

结果是 userName eg = Domain\username


Sim*_*ver 11

我不得不说我很惊讶HttpContext在构造函数中为null。我确定是出于性能原因。已确认IPrincipal按如下所述使用确实会将其注入到构造函数中。它的作用基本上与接受的答案相同,但是采用的是更界面的方式。


对于任何发现此问题的人,寻找通用“如何获得当前用户?”的答案 您可以User直接从访问Controller.User。但是您只能在操作方法内部执行此操作(我想是因为控制器并不仅出于性能原因而与HttpContexts一起运行)。

但是,如果您在构造函数中需要它(如OP一样),或者需要创建需要当前用户的其他可注入对象,则下面是一种更好的方法:

注入IPrincipal以获取用户

第一次见到IPrincipalIIdentity

public interface IPrincipal
{
    IIdentity Identity { get; }
    bool IsInRole(string role);
}

public interface IIdentity
{
    string AuthenticationType { get; }
    bool IsAuthenticated { get; }
    string Name { get; }
}
Run Code Online (Sandbox Code Playgroud)

IPrincipalIIdentity代表用户名和用户名。如果“校长”听起来很奇怪,维基百科将为您提供安慰

重要的是要意识到,不管你得到它IHttpContextAccessor.HttpContext.UserControllerBase.User或者ControllerBase.HttpContext.User获得该保证是一个目标ClaimsPrincipal对象,它实现IPrincipal

ASP.NET User现在没有其他类型的用户(但这并不是说其他​​无法实现的用户IPrincipal)。

因此,如果您要注入的东西依赖于“当前用户名”,则应该注入IPrincipal而不是绝对注入IHttpContextAccessor

重要提示:不要浪费时间IPrincipal直接注入控制器或操作方法-这毫无意义,因为User您已经可以使用它了。

startup.cs

   // Inject IPrincipal
   services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Run Code Online (Sandbox Code Playgroud)

然后,在需要用户的DI对象中,只需注入IPrincipal即可获取当前用户。

这里最重要的事情是如果你在做单元测试,你不需要发送一个HttpContext,而只需要模拟IPrincipal 那些可以 代表的东西ClaimsPrincipal

我不确定100%的另一件重要事情。如果您需要访问的实际索赔,则ClaimsPrincipal需要转换IPrincipalClaimsPrincipal。很好,因为我们知道在运行时100%就是这种类型的(因为这就是事实HttpContext.User)。我实际上很喜欢在构造函数中执行此操作,因为我已经确定IPrincipal 可以肯定会有一个ClaimsPrincipal

如果您要进行模拟,则只需直接创建一个ClaimsPrincipal并将其传递给takes即可IPrincipal

到底为什么没有接口,IClaimsPrincipal我不确定。我认为MS认为那ClaimsPrincipal只是一个不需要接口的专门“集合”。

  • 这使您可以在应用程序中的任何位置注入当前用户,这是一个很好的答案! (2认同)
  • 这不起作用。对于注入的“IPrincipal”,我总是得到“null”。我还需要将瞬态服务添加为 `...GetService&lt;IHttpContextAccessor&gt;()?.HttpContext.User...`(使用 `?`),否则它会崩溃(GetService 返回 null)。 (2认同)

Ali*_*odi 10

我知道这里有很多正确的答案,对于所有这些,我介绍这个技巧:

在 StartUp.cs 中

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Run Code Online (Sandbox Code Playgroud)

然后在任何需要 HttpContext 的地方都可以使用:

var httpContext = new HttpContextAccessor().HttpContext;
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你 ;)


Mik*_*ara 5

我的问题是将登录用户作为 cshtml 文件中的对象访问。考虑到您想要 ViewData 中的用户,这种方法可能会有所帮助:

在 cshtml 文件中

@using Microsoft.AspNetCore.Identity
@inject UserManager<ApplicationUser> UserManager

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
    @UserManager.FindByNameAsync(UserManager.GetUserName(User)).Result.Email
    </title>
  </head>
  <body>

  </body>
</html>
Run Code Online (Sandbox Code Playgroud)


Ale*_*man 5

除了现有的答案之外,我想补充一点,您还可以在应用程序范围内拥有一个可用的类实例,其中包含与用户相关的数据等UserID

它可能对重构 有用,例如 您不想UserID在每个控制器操作中获取并UserID在与服务层相关的每个方法中声明额外的参数。

我做了一项研究,这是我的帖子

DbContext您只需通过添加属性来扩展派生类UserId(或实现Session具有此属性的自定义类)。

在过滤器级别,您可以获取类实例并设置UserId值。

之后,无论您在何处注入实例,它都将具有必要的数据(生命周期必须是每个请求,因此您可以使用AddScoped方法注册它)。

工作示例:

public class AppInitializationFilter : IAsyncActionFilter
{
    private DBContextWithUserAuditing _dbContext;

    public AppInitializationFilter(
        DBContextWithUserAuditing dbContext
        )
    {
        _dbContext = dbContext;
    }

    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next
        )
    {
        string userId = null;
        int? tenantId = null;

        var claimsIdentity = (ClaimsIdentity)context.HttpContext.User.Identity;

        var userIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
        if (userIdClaim != null)
        {
            userId = userIdClaim.Value;
        }

        var tenantIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == CustomClaims.TenantId);
        if (tenantIdClaim != null)
        {
            tenantId = !string.IsNullOrEmpty(tenantIdClaim.Value) ? int.Parse(tenantIdClaim.Value) : (int?)null;
        }

        _dbContext.UserId = userId;
        _dbContext.TenantId = tenantId;

        var resultContext = await next();
    }
}
Run Code Online (Sandbox Code Playgroud)

更多信息请参阅我的回答