Cómo extender las propiedades disponibles de User.Identity

Estoy usando MVC5 Identity 2.0 para que los usuarios inicien sesión en mi sitio web, donde los detalles de autenticación se almacenan en una base de datos SQL. Asp.net Identity se ha implementado de forma estándar, como se puede encontrar en muchos tutoriales en línea.

La clase ApplicationUser en IdentityModels se ha ampliado para incluir algunas propiedades personalizadas, como un entero OrganizationId. La idea es que muchos usuarios pueden crearse y asignarse a una organización común para fines de relación con la base de datos.

public class ApplicationUser : IdentityUser { public async Task GenerateUserIdentityAsync(UserManager manager) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); // Add custom user claims here return userIdentity; } //Extended Properties public DateTime? BirthDate { get; set; } public long? OrganizationId { get; set; } //Key Mappings [ForeignKey("OrganizationId")] public virtual Organization Organization { get; set; } } 

¿Cómo puedo recuperar la propiedad OrganizationId del usuario actualmente conectado desde dentro de un controlador? ¿Está disponible a través de un método una vez que el usuario inicia sesión o siempre tengo que recuperar OrganizationId de la base de datos, en función del UserId, cada vez que se ejecuta un método de controlador?

Leyendo en la web, he visto que necesito usar lo siguiente para obtener el UserId conectado, etc.

 using Microsoft.AspNet.Identity; ... User.Identity.GetUserId(); 

Sin embargo, OrganizationId no es una propiedad disponible en User.Identity. ¿Debo extender User.Identity para incluir la propiedad OrganizationId? Si es así, ¿cómo hago esto?

El motivo por el que necesito OrganizationId con tanta frecuencia es que muchas consultas de tabla dependen de OrganizationId para recuperar datos relevantes para la Organización que están asociados al usuario que ha iniciado sesión.

Siempre que desee extender las propiedades de User.Identity con cualquier propiedad adicional como la pregunta anterior, agregue estas propiedades primero a la clase ApplicationUser como esta:

 public class ApplicationUser : IdentityUser { public async Task GenerateUserIdentityAsync(UserManager manager) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); // Add custom user claims here return userIdentity; } // Your Extended Properties public long? OrganizationId { get; set; } } 

Entonces, lo que necesita es crear un método de extensión como ese (creo el mío en una nueva carpeta de extensiones):

 namespace App.Extensions { public static class IdentityExtensions { public static string GetOrganizationId(this IIdentity identity) { var claim = ((ClaimsIdentity)identity).FindFirst("OrganizationId"); // Test for null to avoid issues during local testing return (claim != null) ? claim.Value : string.Empty; } } } 

Cuando crea la Identidad en la clase ApplicationUser, simplemente agregue Claim -> OrganizationId de esta manera:

  public async Task GenerateUserIdentityAsync(UserManager manager) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); // Add custom user claims here => this.OrganizationId is a value stored in database against the user userIdentity.AddClaim(new Claim("OrganizationId", this.OrganizationId.ToString())); return userIdentity; } 

Una vez que haya agregado el reclamo y tenga su método de extensión en su lugar, para que esté disponible como propiedad en su User.Identity, agregue una statement de uso en la página o archivo al que desea acceder :

en mi caso: using App.Extensions; dentro de un Controlador y @using. App.Extensions @using. App.Extensions .cshtml View file.

EDITAR:

Lo que también puede hacer para evitar agregar una instrucción de uso en cada Vista es ir a la carpeta Vistas y ubicar allí el archivo Web.config. Ahora busque la etiqueta y agregue su espacio de nombres de extensión allí de la siguiente manera:

  

Guarde su archivo y listo. Ahora cada Vista sabrá de sus extensiones.

Puede acceder al Método de Extensión:

 var orgId = User.Identity.GetOrganizationId(); 

Espero que ayude a alguien 🙂

Estaba buscando la misma solución y Pawel me dio el 99% de la respuesta. Lo único que faltaba que necesitaba para que se mostrara la Extensión era agregar el siguiente Código Razor a la página cshtml (ver):

@using programname.Models.Extensions

Estaba buscando el FirstName, para mostrar en la parte superior derecha de mi NavBar después de que el usuario inició sesión.

Pensé que publicaría esto en caso de que ayudara a alguien más, así que aquí está mi código:

Creé una nueva carpeta llamada Extensions (Under my Models Folder) y creé la nueva clase como Pawel especificada arriba: IdentityExtensions.cs

 using System.Security.Claims; using System.Security.Principal; namespace ProgramName.Models.Extensions { public static class IdentityExtensions { public static string GetUserFirstname(this IIdentity identity) { var claim = ((ClaimsIdentity)identity).FindFirst("FirstName"); // Test for null to avoid issues during local testing return (claim != null) ? claim.Value : string.Empty; } } } 

IdentityModels.cs :

 public class ApplicationUser : IdentityUser { //Extended Properties public string FirstName { get; internal set; } public string Surname { get; internal set; } public bool isAuthorized { get; set; } public bool isActive { get; set; } public async Task GenerateUserIdentityAsync(UserManager manager) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); // Add custom user claims here userIdentity.AddClaim(new Claim("FirstName", this.FirstName)); return userIdentity; } } 

Luego en mi _LoginPartial.cshtml (en Views/Shared Carpetas Views/Shared ) agregué @using.ProgramName.Models.Extensions

Luego agregué el cambio a la siguiente línea de código que iba a usar el nombre del usuario después de iniciar sesión:

@Html.ActionLink("Hello " + User.Identity.GetUserFirstname() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })

Tal vez esto ayude a alguien más en la línea.

Echa un vistazo a esta excelente publicación de John Atten: ASP.NET Identity 2.0: personalización de usuarios y roles

Tiene una gran información paso a paso sobre todo el proceso. Ve a leerlo:)

Estos son algunos de los conceptos básicos.

Extienda la clase ApplicationUser por defecto agregando nuevas propiedades (es decir, dirección, ciudad, estado, etc.):

 public class ApplicationUser : IdentityUser { public async Task GenerateUserIdentityAsync(UserManager manager) { var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); return userIdentity; } public string Address { get; set; } public string City { get; set; } public string State { get; set; } // Use a sensible display name for views: [Display(Name = "Postal Code")] public string PostalCode { get; set; } // Concatenate the address info for display in tables and such: public string DisplayAddress { get { string dspAddress = string.IsNullOrWhiteSpace(this.Address) ? "" : this.Address; string dspCity = string.IsNullOrWhiteSpace(this.City) ? "" : this.City; string dspState = string.IsNullOrWhiteSpace(this.State) ? "" : this.State; string dspPostalCode = string.IsNullOrWhiteSpace(this.PostalCode) ? "" : this.PostalCode; return string.Format("{0} {1} {2} {3}", dspAddress, dspCity, dspState, dspPostalCode); } } 

Luego agrega sus nuevas propiedades a su RegisterViewModel.

  // Add the new address properties: public string Address { get; set; } public string City { get; set; } public string State { get; set; } 

Luego actualice la vista de registro para incluir las nuevas propiedades.

  
@Html.LabelFor(m => m.Address, new { @class = "col-md-2 control-label" })
@Html.TextBoxFor(m => m.Address, new { @class = "form-control" })

Luego actualice el método Register () en AccountController con las nuevas propiedades.

  // Add the Address properties: user.Address = model.Address; user.City = model.City; user.State = model.State; user.PostalCode = model.PostalCode; 

Dhaust ofrece una buena manera de agregar la propiedad a la clase ApplicationUser. Al mirar el código OP, parece que pudieron haberlo hecho o estaban en camino de hacerlo. La pregunta pregunta

¿Cómo puedo recuperar la propiedad OrganizationId del usuario actualmente conectado desde dentro de un controlador? Sin embargo, OrganizationId no es una propiedad disponible en User.Identity. ¿Debo extender User.Identity para incluir la propiedad OrganizationId?

Pawel ofrece una forma de agregar un método de extensión que requiere el uso de sentencias o agregar el espacio de nombres al archivo web.config.

Sin embargo, la pregunta pregunta si “necesita” extender User.Identity para incluir la nueva propiedad. Existe una forma alternativa de acceder a la propiedad sin extender User.Identity. Si siguió el método de Dhaust, puede usar el siguiente código en su controlador para acceder a la nueva propiedad.

 ApplicationDbContext db = new ApplicationDbContext(); var manager = new UserManager(new UserStore(db)); var currentUser = manager.FindById(User.Identity.GetUserId()); var myNewProperty = currentUser.OrganizationId; 

También agregué o extendí columnas adicionales en mi tabla AspNetUsers. Cuando simplemente quería ver estos datos, encontré muchos ejemplos como el código anterior con “Extensiones”, etc. Esto realmente me sorprendió de que tuviera que escribir todas esas líneas de código solo para obtener un par de valores de los usuarios actuales.

Resulta que puede consultar la tabla AspNetUsers como cualquier otra tabla:

  ApplicationDbContext db = new ApplicationDbContext(); var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault(); 

Para cualquiera que encuentre esta pregunta buscando cómo acceder a propiedades personalizadas en ASP.NET Core 2.1, es mucho más fácil: tendrá un UserManager, por ejemplo, en _LoginPartial.cshtml, y luego simplemente puede hacerlo (suponiendo que “ScreenName” es un propiedad que ha agregado a su propio AppUser que hereda de IdentityUser):

 @using Microsoft.AspNetCore.Identity @using  @inject SignInManager SignInManager @inject UserManager UserManager @if (SignInManager.IsSignedIn(User)) { 
} else { }