Как получить текущего пользователя в ядре asp.net

Я хочу получить текущего пользователя для получения информации о пользователе, такой как электронная почта. Но я не могу сделать это в ядре asp.net. я весьма озадачен Это мой код

HttpContext почти равен нулю в конструкторе контроллера. Это не хорошо, чтобы получить пользователя в каждом действии. Я хочу получить информацию о пользователе один раз и установить ее в ViewData;

    public DashboardController()
    {
        var user = HttpContext.User.GetUserId();
   }

Ответ 1

User.FindFirst(ClaimTypes.NameIdentifier).Value

EDIT для конструктора

Ниже работает код:

public Controller(IHttpContextAccessor httpContextAccessor)
{
    var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value 
}

Изменить для RTM

Вам следует зарегистрировать IHttpContextAccessor:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }

Ответ 2

Простой способ, который работает, и я проверил.

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

var user = await _userManager.GetUserAsync(HttpContext.User);

тогда вы можете все свойства этой переменной, как user.Email. Надеюсь, это кому-нибудь поможет.

Редактирование:

Это очевидно простая вещь, но немного сложная причина различных типов систем аутентификации в ASP.NET Core. Я обновляюсь, потому что некоторые люди получают null.

Для проверки подлинности JWT (протестировано на ASP.NET Core v3.0.0-preview7):

var email = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;

var user = await _userManager.FindByEmailAsync(email);

Ответ 3

Есть еще один способ получить текущего пользователя в 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;
}  

Этот код отправляется в контроллер с именем DemoController. Не будет работать без обоих ждать (не скомпилировать);)

Ответ 4

Похоже, что на данный момент (апрель 2017 года) работает следующее:

public string LoggedInUser => User.Identity;

По крайней мере, в пределах Controller

Ответ 5

Я должен сказать, что был довольно удивлен, что HttpContext является нулевым внутри конструктора. Я уверен, что по причинам производительности. Подтвердили, что при использовании IPrincipal, как описано ниже, он вводится в конструктор. По сути, он делает то же самое, что и принятый ответ, но более понятным способом.


Для любого, кто найдет этот вопрос, ищет ответ на общий вопрос "Как получить текущего пользователя?" Вы можете просто получить доступ к User прямо из Controller.User. Но вы можете сделать это только внутри методов действия (я полагаю, потому что контроллеры работают не только с HttpContexts и по соображениям производительности).

Однако - если вам это нужно в конструкторе (как это делал OP) или вам нужно создавать другие инъецируемые объекты, которым нужен текущий пользователь, тогда лучше использовать следующий метод:

Введите IPrincipal, чтобы получить пользователя

Первая встреча IPrincipal и IIdentity

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

public interface IIdentity
{
    string AuthenticationType { get; }
    bool IsAuthenticated { get; }
    string Name { get; }
}

IPrincipal и IIdentity представляют пользователя и имя пользователя. Википедия вас утешит, если "Принципал" будет звучать странно.

Важно понимать, что независимо от того, получаете ли вы его из IHttpContextAccessor.HttpContext.User, ControllerBase.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);

Затем в вашем DI-объекте, для которого нужен пользователь, вы просто вводите IPrincipal, чтобы получить текущего пользователя.

Самое важное здесь, если вы выполняете модульные тесты, вам не нужно отправлять HttpContext, а нужно только имитировать что-то, представляющее IPrincipal , что может быть просто ClaimsPrincipal.

Еще одна важная вещь, в которой я не уверен на 100%. Если вам нужен доступ к фактическим заявкам из ClaimsPrincipal, вам необходимо привести IPrincipal к ClaimsPrincipal. Это хорошо, так как мы знаем на 100%, что во время выполнения он такого типа (поскольку это то, что HttpContext.User). На самом деле мне нравится просто делать это в конструкторе, так как я уже точно знаю, что любой IPrincipal будет ClaimsPrincipal.

Если вы делаете насмешку, просто создайте ClaimsPrincipal напрямую и передайте его любому, что займет IPrincipal.

Точно, почему нет интерфейса для IClaimsPrincipal, я не уверен. Я предполагаю, что MS решила, что ClaimsPrincipal была просто специализированной "коллекцией", которая не гарантировала интерфейс.

Ответ 6

Моя проблема состояла в том, чтобы получить доступ к зарегистрированному пользователю как объект в файле 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>

Ответ 7

В дополнение к существующим ответам я хотел бы добавить, что у вас также может быть доступный экземпляр класса для всего приложения, который содержит данные, относящиеся к пользователю, такие как UserID и т.д.

Это может быть полезно для рефакторинга, например, вы не хотите извлекать UserID в каждом действии контроллера и объявлять дополнительный параметр UserID в каждом методе, связанном с Service Layer.

Я провел исследование и вот мой пост.

Вы просто расширяете свой класс, производный от DbContext, добавляя свойство UserId (или реализуете собственный класс Session который имеет это свойство).

На уровне фильтра вы можете получить экземпляр вашего класса и установить значение UserId.

После этого, куда бы вы ни внедрили свой экземпляр - он будет иметь необходимые данные (время жизни должно быть на запрос, поэтому вы регистрируете его с AddScoped метода 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();
    }
}

Для получения дополнительной информации см. Мой ответ.

Ответ 8

Принимая IdentityUser также будет работать. Это текущий объект пользователя, и все значения пользователя могут быть получены.

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

var user = await _userManager.GetUserAsync(HttpContext.User);

Ответ 9

Если вы используете удостоверение в скаффолде и используете Asp.net Core 2. 2+, вы можете получить доступ к текущему пользователю из вида, подобного следующему:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

 @if (SignInManager.IsSignedIn(User))
    {
        <p>Hello @User.Identity.Name!</p>
    }
    else
    {
        <p>You're not signed in!</p>
    }

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.2&tabs=visual-studio

Ответ 10

Это старый вопрос, но мой случай показывает, что мой случай здесь не обсуждался.

Мне больше всего нравится ответ Simon_Weaver (fooobar.com/questions/148447/...). Он подробно объясняет, как получить имя пользователя, используя IPrincipal и IIdentity. Этот ответ абсолютно правильный, и я рекомендую использовать этот подход. Однако во время отладки я столкнулся с проблемой, когда ASP.NET НЕ может правильно заполнить принцип обслуживания. (или, другими словами, IPrincipal.Identity.Name имеет значение null)

Очевидно, что для получения имени пользователя MVC framework его нужно откуда-то взять. В мире .NET ASP.NET или ASP.NET Core используют промежуточное программное обеспечение Open ID Connect. В простом сценарии веб-приложения аутентифицируют пользователя в веб-браузере. В этом случае веб-приложение направляет браузер пользователей для входа в Azure AD. Azure AD возвращает ответ о входе через браузер пользователей, который содержит утверждения о пользователе в маркере безопасности. Чтобы это работало в коде вашего приложения, вам необходимо предоставить полномочия, которым ваше веб-приложение делегирует вход в систему. При развертывании веб-приложения в службе Azure общий сценарий, отвечающий этим требованиям, заключается в настройке веб-приложения: "Службы приложения" → YourApp → "Аутентификация/Авторизация" → "Аутентификация службы приложения" = "Вкл" и т.д.https://github.com/Huachao/azure-content/blob/master/articles/app-service-api/app-service-api-authentication.md Я верю (это мое образованное предположение), что под капотом этого процесса мастер настраивает "родительскую" веб-конфигурацию этого веб-приложения, добавляя те же параметры, которые я показываю в следующих параграфах. По сути, проблема, почему этот подход НЕ работает в ASP.NET Core, заключается в том, что конфигурация "родительского" компьютера игнорируется webconfig. (это не на 100% уверен, я просто даю лучшее объяснение, которое у меня есть). Таким образом, чтобы это работало, вам нужно настроить это вручную в вашем приложении.

Вот статья, в которой объясняется, как вручную настроить приложение для использования Azure AD. https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/aspnetcore2-2

Шаг 1. Зарегистрируйте образец у своего клиента Azure AD. (очевидно, я не хочу тратить время на объяснения).

Шаг 2: В файле appsettings.json: замените значение ClientID идентификатором приложения из приложения, которое вы зарегистрировали на портале регистрации приложений на шаге 1. замените значение TenantId на общее

Шаг 3. Откройте файл Startup.cs и в методе ConfigureServices после строки, содержащей .AddAzureAD, вставьте следующий код, который позволяет вашему приложению входить в систему пользователей с помощью конечной точки Azure AD v2.0, то есть Work и School и Личные учетные записи Microsoft.

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.Authority = options.Authority + "/v2.0/";
    options.TokenValidationParameters.ValidateIssuer = false;
});

Резюме: я показал еще одну возможную проблему, которая могла привести к ошибке, описанной автором темы. Причиной этой проблемы является отсутствие конфигураций для Azure AD (промежуточное программное обеспечение Open ID). Для решения этой проблемы я предлагаю вручную настроить "Аутентификация/Авторизация". Краткий обзор того, как настроить это, добавлен.

Ответ 11

Возможно, я не видел ответа, но так я это делаю.

  1. .Net Core → Свойства → launchSettings.json

Вам нужно изменить эти значения

"windowsAuthentication": true, // needs to be true
"anonymousAuthentication": false,  // needs to be false 

Startup.cs → ConfigureServices (...)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

MVC или контроллер Web Api

private readonly IHttpContextAccessor _httpContextAccessor;
//constructor then
_httpContextAccessor = httpContextAccessor;

Метод контроллера:

string userName = _httpContextAccessor.HttpContext.User.Identity.Name;

Результат - имя пользователя, например = Домен\имя пользователя

Ответ 12

Я получил свое решение

var claim = HttpContext.User.CurrentUserID();

public static class XYZ
{
    public static int CurrentUserID(this ClaimsPrincipal claim)
    {
        var userID = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
         "UserID").Value;
        return Convert.ToInt32(userID);
    }
    public static string CurrentUserRole(this ClaimsPrincipal claim)
    {
        var role = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
        "Role").Value;
        return role;
    }
}