Cómo obtener un usuario actual en asp.net core

Resuelto Mehran Hafizi asked hace 8 años • 21 respuestas

Quiero obtener el usuario actual para poder acceder a campos como su dirección de correo electrónico. Pero no puedo hacer eso en el núcleo de asp.net. Este es mi código:

HttpContextcasi es nulo en el constructor del controlador. No es bueno tener un usuario en cada acción. Quiero obtener la información del usuario una vez y guardarla en ViewData;

public DashboardController()
{
    var user = HttpContext.User.GetUserId();
}
Mehran Hafizi avatar Apr 15 '16 14:04 Mehran Hafizi
Aceptado
User.FindFirst(ClaimTypes.NameIdentifier).Value

EDITAR para constructor

El siguiente código funciona:

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

Editar para RTM

Deberías registrarte IHttpContextAccessor:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
    }
adem caglin avatar Apr 15 '2016 08:04 adem caglin

Manera simple que funciona y lo comprobé.

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

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

entonces puedes conocer todas las propiedades de estas variables como user.Email. Espero que esto ayude a alguien.

Editar :

Es algo aparentemente simple pero un poco complicado debido a los diferentes tipos de sistemas de autenticación en ASP.NET Core. Actualizo porque algunas personas lo están recibiendo null.

Para autenticación JWT (probado en ASP.NET Core v3.0.0-preview7):

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

var user = await _userManager.FindByEmailAsync(email);
Ahmad avatar Feb 27 '2017 18:02 Ahmad

Debo decir que me sorprendió bastante que HttpContext sea nulo dentro del constructor. Estoy seguro de que es por motivos de rendimiento. He confirmado que usar IPrincipalcomo se describe a continuación lo inyecta en el constructor. Básicamente, hace lo mismo que la respuesta aceptada, pero de una manera más interfaz.


Para cualquiera que encuentre esta pregunta y busque una respuesta a la pregunta genérica "¿Cómo obtener un usuario actual?" puedes acceder Userdirectamente desde Controller.User. Pero solo puedes hacer esto dentro de los métodos de acción (supongo que porque los controladores no solo se ejecutan con HttpContexts y por razones de rendimiento).

Sin embargo, si lo necesita en el constructor (como lo hizo OP) o necesita crear otros objetos inyectables que necesitan el usuario actual, el siguiente es un mejor enfoque:

Inyecte IPrincipal para obtener usuario

primer encuentro IPrincipalyIIdentity

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

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

IPrincipaly IIdentityrepresenta el usuario y el nombre de usuario. "Wikipedia lo consolará si 'Director' suena extraño ".

Es importante tener en cuenta que, ya sea que lo obtenga de IHttpContextAccessor.HttpContext.User, ControllerBase.Usero ControllerBase.HttpContext.Userque obtenga un objeto, se garantiza que será un ClaimsPrincipalobjeto que implementeIPrincipal .

No hay ningún otro tipo de usuario que ASP.NET utilice en Usereste momento (pero eso no quiere decir que otra cosa no pueda implementarse IPrincipal).

Entonces, si tiene algo que depende del 'nombre de usuario actual' que desea inyectar, debería inyectarlo IPrincipaly definitivamente no IHttpContextAccessor.

Importante: No pierda el tiempo inyectando IPrincipaldirectamente en su controlador o método de acción; no tiene sentido ya que Userya está disponible allí.

En startup.cs:

// Inject IPrincipal
services.AddHttpContextAccessor();
services.AddTransient<IPrincipal>(
    provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);

Luego, en su objeto DI que necesita el usuario, simplemente inyecta IPrincipalpara obtener el usuario actual.

Lo más importante aquí es que si estás haciendo pruebas unitarias, no necesitas enviar un HttpContext, solo necesitas simular algo que represente IPrincipal lo que puede ser simplemente ClaimsPrincipal .

Una cosa extra importante de la que no estoy 100% seguro. Si necesita acceder a las reclamaciones reales, ClaimsPrincipaldebe enviarlas IPrincipala ClaimsPrincipal. Esto está bien ya que sabemos al 100% que en tiempo de ejecución es de ese tipo (ya que eso es lo que HttpContext.Useres). De hecho, me gusta hacer esto en el constructor porque ya sé con certeza que cualquiera IPrincipal será un archivo ClaimsPrincipal.

Si te estás burlando, simplemente crea un ClaimsPrincipaldirectamente y pásalo a lo que sea necesario IPrincipal.

IClaimsPrincipalNo estoy seguro exactamente por qué no hay una interfaz . Supongo que MS decidió que ClaimsPrincipalera sólo una "colección" especializada que no justificaba una interfaz.

Simon_Weaver avatar Jan 28 '2019 22:01 Simon_Weaver