ASP.NET MVC 5 - Identidad. Cómo obtener el ApplicationUser actual

237

Tengo una entidad Artículo en mi proyecto que tiene la ApplicationUserpropiedad nombrada Author. ¿Cómo puedo obtener el objeto completo de la sesión actualmente ApplicationUser? Al crear un nuevo artículo, tengo que establecer la Authorpropiedad en Articlela actual ApplicationUser.

En el antiguo mecanismo de Membresía era simple, pero en el nuevo enfoque de Identidad no sé cómo hacer esto.

Traté de hacerlo de esta manera:

  • Agregar declaración de uso para extensiones de identidad: using Microsoft.AspNet.Identity;
  • Luego trato de obtener el usuario actual: ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == User.Identity.GetUserId());

Pero me sale la siguiente excepción:

LINQ to Entities no reconoce el método 'System.String GetUserId (System.Security.Principal.IIdentity)', y este método no se puede traducir a una expresión de tienda. Fuente = EntityFramework

Ellbar
fuente

Respuestas:

448

No debería necesitar consultar la base de datos directamente para el usuario de la aplicación actual.

Eso introduce una nueva dependencia de tener un contexto adicional para empezar, pero en el futuro las tablas de la base de datos de usuarios cambian (3 veces en los últimos 2 años) pero la API es consistente. Por ejemplo, la userstabla ahora se llama AspNetUsersen Identity Framework, y los nombres de varios campos clave principales se mantuvieron cambiantes, por lo que el código en varias respuestas ya no funcionará tal cual .

Otro problema es que el acceso OWIN subyacente a la base de datos utilizará un contexto separado, por lo que los cambios del acceso SQL separado pueden producir resultados no válidos (por ejemplo, no ver los cambios realizados en la base de datos). Una vez más, la solución es el trabajo con el API proporcionado y no trata de trabajo en torno a ella.

La forma correcta de acceder al objeto de usuario actual en la identidad ASP.Net (a esta fecha) es:

var user = UserManager.FindById(User.Identity.GetUserId());

o, si tiene una acción asíncrona, algo como:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

FindByIdrequiere que tenga la siguiente instrucción de uso para que los UserManagermétodos no asíncronos estén disponibles (son métodos de extensión para UserManager, por lo que si no incluye esto, solo verá FindByIdAsync):

using Microsoft.AspNet.Identity;

Si no está en un controlador en absoluto (por ejemplo, está usando la inyección de IOC), la identificación de usuario se recupera por completo de:

System.Web.HttpContext.Current.User.Identity.GetUserId();

Si no está en el controlador de cuenta estándar, deberá agregar lo siguiente (como ejemplo) a su controlador:

1. Agregue estas dos propiedades:

    /// <summary>
    /// Application DB context
    /// </summary>
    protected ApplicationDbContext ApplicationDbContext { get; set; }

    /// <summary>
    /// User manager - attached to application DB context
    /// </summary>
    protected UserManager<ApplicationUser> UserManager { get; set; }

2. Agregue esto en el constructor del controlador:

    this.ApplicationDbContext = new ApplicationDbContext();
    this.UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(this.ApplicationDbContext));

Actualización de marzo de 2015

Nota: La actualización más reciente del marco de Identity cambia una de las clases subyacentes utilizadas para la autenticación. Ahora puede acceder desde el Contexto Owin del Contenido Http actual.

ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());

Apéndice:

Al usar EF e Identity Framework con Azure, a través de una conexión de base de datos remota (por ejemplo, pruebas de host local a la base de datos de Azure), puede golpear aleatoriamente el temido "error: 19 - La conexión física no es utilizable". Como la causa está oculta dentro de Identity Framework, donde no puede agregar reintentos (o lo que parece faltar .Include(x->someTable)), debe implementar una costumbre SqlAzureExecutionStrategyen su proyecto.

Codificación ido
fuente
55
@TBA: gracias, más tarde me di cuenta de que es un método de extensión. Necesita agregar Microsoft.AspNet.Identity usando. gracias de nuevo
Sentinel
2
No se pudo encontrar el tipo o nombre de usuario UserStore. Agregué usando
Microsft.AspNet.Indentity
2
@Zapnologica: Eso suena como una nueva pregunta (te sugiero que la publiques). Puede extender la ApplicationUserclase (específica de la aplicación) y la AspNetUserstabla en paralelo y proporcionarán cualquier campo nuevo. Nuevamente: ¡No golpee la base de datos directamente! :)
Gone Coding
2
@ LifeH2O: el ApplicationUser devuelto por FindById es su clase, completa con sus propiedades adicionales. Por favor pruebalo.
Gone Coding
1
Esperando su nueva solución: P
Anup Sharma
60

Mi error, no debería haber usado un método dentro de una consulta LINQ.

Código correcto:

using Microsoft.AspNet.Identity;


string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
Ellbar
fuente
2
User.Identiy.GetUserId no existe para mí. ¿Es ese el método personalizado? Solo me pongo en contacto con User.Identity
Gerrie Pretorius
99
No importa ... necesita el "uso de Microsoft.AspNet.Identity"; para que ese método esté ahí.
Gerrie Pretorius
44
Solo una nota, el objeto Usuario solo es visible en Controladores.
Miro J.
8
¿Seguramente deberías usar UserManagermétodos y no golpear la base de datos directamente?
Se fue la codificación el
3
@Josh Bjelovuk: nunca acceda a una base de datos directamente cuando haya una API disponible. Eso introduce una nueva dependencia de tener un contexto adicional para empezar, pero en el futuro las tablas de la base de datos de usuarios cambian (3 veces en los últimos 2 años) pero la API es consistente.
Gone Coding
33

Está en los comentarios de las respuestas, pero nadie ha publicado esto como la solución real.

Solo necesita agregar una declaración de uso en la parte superior:

using Microsoft.AspNet.Identity;
rtpHarry
fuente
2
Vine aquí con esa excepción, lo resolví con eso using. Al ver que 15.000 personas visitaron la pregunta, pensé que era una respuesta útil :)
rtpHarry
2
@TrueBlueAussie, a pesar de no ser una respuesta directa a la pregunta de los OP, siento que mencionar el uso es una adición muy útil.
StuartQ
1
Para mayor claridad, es porque .GetUserId()es un método de extensión
FSCKur
11

¡El código de Ellbar funciona! Solo necesitas agregar usando.

1 - using Microsoft.AspNet.Identity;

Y ... el código de Ellbar:

2 - string currentUserId = User.Identity.GetUserId(); ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);

Con este código (en currentUser), trabaja los datos generales del usuario conectado, si desea datos adicionales ... vea este enlace

Diego Borges
fuente
55
Puede "funcionar", pero ciertamente no se recomienda omitir la API suministrada y acceder directamente a la base de datos. Si utilizó la API, no necesitaría trabajo adicional para obtener los datos adicionales, ya que ya estaría en el ApplicationUserobjeto
Codificación Gone
¡Estoy de acuerdo! Sin embargo, recurrí de esta manera porque ya tenía un sistema en funcionamiento hoy, con una ejecución en la base de datos y ¡necesito una solución simple para resolver este problema! Ciertamente, en un sistema temprano, pondría objetos en sus clases e identidades adecuadas.
Diego Borges
6

A partir de ASP.NET Identity 3.0.0, esto se ha refactorizado en

//returns the userid claim value if present, otherwise returns null
User.GetUserId();
Seth IK
fuente
6
ApplicationDbContext context = new ApplicationDbContext();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
ApplicationUser currentUser = UserManager.FindById(User.Identity.GetUserId());

string ID = currentUser.Id;
string Email = currentUser.Email;
string Username = currentUser.UserName;
Majid joghataey
fuente
3

Para MVC 5 solo mire dentro del método EnableTwoFactorAuthentication de ManageController en el andamio de plantillas de WebApplication, se está haciendo allí:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> EnableTwoFactorAuthentication()
        {
            await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
            var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
            if (user != null)
            {
                await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
            }
            return RedirectToAction("Index", "Manage");
        }

La respuesta está ahí, como lo sugiere el propio Microsoft:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

Tendrá todas las propiedades adicionales que definió en la clase ApplicationUser.

Paceman
fuente
55
Ya cubierto Compruebe que no se haya publicado una respuesta idéntica (o agregue un comentario a una respuesta existente) :)
Gone Coding
3

En este momento, la plantilla de proyecto asp.mvc crea un controlador de cuenta que obtiene el administrador de usuario de esta manera:

HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>()

Lo siguiente funciona para mí:

ApplicationUser user = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(User.Identity.GetUserId());
Holger Thiemann
fuente
0

Estaba disponible con éxito para obtener el Usuario de la aplicación siguiendo un fragmento de código

var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            var user = manager.FindById(User.Identity.GetUserId());
            ApplicationUser EmpUser = user;
Abdul Hannan
fuente
0

En caso de que alguien esté trabajando con Identityusuarios web forms, lo hice funcionar al hacerlo:

var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindById(User.Identity.GetUserId());
Jamshaid Kamran
fuente