Cómo cambiar el tipo de identificación en Microsoft.AspNet.Identity.EntityFramework.IdentityUser

(ASP.NET MVC 5, EF6, VS2013)

Estoy intentando descubrir cómo cambiar el tipo del campo “Id” de la cadena a int en el tipo:

Microsoft.AspNet.Identity.EntityFramework.IdentityUser 

para tener nuevas cuentas de usuario asociadas a un ID entero en lugar de un GUID. Pero parece que esto será más complicado que simplemente agregar una nueva propiedad de Id con tipo int en mi clase de usuario derivada. Eche un vistazo a esta firma de método:

(desde ensamblado Microsoft.AspNet.Identity.Core.dll)

 public class UserManager : IDisposable where TUser : global::Microsoft.AspNet.Identity.IUser { ... public virtual Task AddLoginAsync(string userId, UserLoginInfo login); ... } 

Por lo tanto, parece que hay otros métodos integrados en el marco de identidad de ASP.NET que requieren que userId sea una cadena. ¿Tendría que volver a implementar estas clases también?

Una explicación de por qué no quiero almacenar GUID para identificadores en la tabla de usuarios:

-Hay otras tablas que relacionan los datos a la tabla de usuarios a través de una clave externa. (Cuando los usuarios guardan contenido en el sitio). No veo ninguna razón para usar el tipo de campo más grande y gastar más espacio en la base de datos sin ventajas claras. (Sé que hay otras publicaciones sobre el uso de GUID vs int ids, pero parece que muchos sugieren que los IDs int. Son más rápidos y usan menos espacio, lo que todavía me deja preguntándome).

– Planeo exponer un punto final relajante para permitir a los usuarios recuperar datos sobre un usuario en particular. Creo:

 /users/123/name 

es más limpio que

 /users/{af54c891-69ba-4ddf-8cb6-00d368e58d77}/name 

¿Alguien sabe por qué el equipo de ASP.NET decidió implementar identificaciones de esta manera? ¿Estoy siendo miope al tratar de cambiar esto a un tipo int? (Quizás hay beneficios que me falta).

Gracias…

-Ben

Por lo tanto, si desea ID int, debe crear su propia clase POCO IUser e implementar IUserStore para su clase IUser personalizada en la versión 1.0 RTM.

Esto es algo que no tuvimos tiempo de apoyar, pero estoy buscando hacer esto fácil (ier) en 1.1 en este momento. Es de esperar que pronto haya algo disponible en las comstackciones nocturnas.

Actualizado con 1.1-alpha1 ejemplo: Cómo obtener builts nocturnos

Si actualizas las últimas partes nocturnas, puedes probar las nuevas API 1.1-alpha1, que deberían hacer que esto sea más fácil ahora: esto es lo que deberían ser los complementos de Guids en lugar de cadenas, por ejemplo

  public class GuidRole : IdentityRole { public GuidRole() { Id = Guid.NewGuid(); } public GuidRole(string name) : this() { Name = name; } } public class GuidUserRole : IdentityUserRole { } public class GuidUserClaim : IdentityUserClaim { } public class GuidUserLogin : IdentityUserLogin { } public class GuidUser : IdentityUser { public GuidUser() { Id = Guid.NewGuid(); } public GuidUser(string name) : this() { UserName = name; } } private class GuidUserContext : IdentityDbContext { } private class GuidUserStore : UserStore { public GuidUserStore(DbContext context) : base(context) { } } private class GuidRoleStore : RoleStore { public GuidRoleStore(DbContext context) : base(context) { } } [TestMethod] public async Task CustomUserGuidKeyTest() { var manager = new UserManager(new GuidUserStore(new GuidUserContext())); GuidUser[] users = { new GuidUser() { UserName = "test" }, new GuidUser() { UserName = "test1" }, new GuidUser() { UserName = "test2" }, new GuidUser() { UserName = "test3" } }; foreach (var user in users) { UnitTestHelper.IsSuccess(await manager.CreateAsync(user)); } foreach (var user in users) { var u = await manager.FindByIdAsync(user.Id); Assert.IsNotNull(u); Assert.AreEqual(u.UserName, user.UserName); } } 

Utilizando la respuesta de Stefan Cebulak y el gran artículo de blog de Ben Foster ASP.NET Identity Stripped Bare , he llegado a la siguiente solución, que he aplicado a ASP.NET Identity 2.0 con un AccountController Visual Studio 2013 AccountController .

La solución utiliza un número entero como clave principal para los usuarios y también permite obtener una ID del usuario que está conectado actualmente sin hacer un viaje a la base de datos.

Estos son los pasos, debe seguir:

1. Crear clases personalizadas relacionadas con el usuario

De forma predeterminada, AccountController utiliza clases, que utilizan string , como tipo de clave principal. Necesitamos crear debajo de las clases, que usarán un int lugar. AppUser.cs todas las clases a continuación en un archivo: AppUser.cs

 public class AppUser : IdentityUser, IUser { } public class AppUserLogin : IdentityUserLogin { } public class AppUserRole : IdentityUserRole { } public class AppUserClaim : IdentityUserClaim { } public class AppRole : IdentityRole { } 

También será útil tener un ClaimsPrincipal personalizado, que expondrá fácilmente la identificación del usuario

 public class AppClaimsPrincipal : ClaimsPrincipal { public AppClaimsPrincipal( ClaimsPrincipal principal ) : base( principal ) { } public int UserId { get { return int.Parse(this.FindFirst( ClaimTypes.Sid ).Value); } } } 

2. Crea un IdentityDbContext personalizado

El contexto de la base de datos de nuestra aplicación extenderá IdentityDbContext , que implementa de forma predeterminada todos los DbSets relacionados con la autenticación. Incluso si DbContext.OnModelCreating es un método vacío, no estoy seguro acerca de IdentityDbContext.OnModelCreating , por lo tanto, al anular, recuerde llamar a base.OnModelCreating( modelBuilder ) AppDbContext.cs

 public class AppDbContext : IdentityDbContext { public AppDbContext() : base("DefaultConnection") { // Here use initializer of your choice Database.SetInitializer( new CreateDatabaseIfNotExists() ); } // Here you define your own DbSet's protected override void OnModelCreating( DbModelBuilder modelBuilder ) { base.OnModelCreating( modelBuilder ); // Here you can put FluentAPI code or add configuration map's } } 

3. Crear UserStore y UserManager , que usarán arriba

AppUserStore.cs

 public interface IAppUserStore : IUserStore { } public class AppUserStore : UserStore, IAppUserStore { public AppUserStore() : base( new AppDbContext() ) { } public AppUserStore(AppDbContext context) : base(context) { } } 

AppUserManager.cs

 public class AppUserManager : UserManager { public AppUserManager( IAppUserStore store ) : base( store ) { } } 

4. Modifique AccountController para usar sus clases personalizadas

Cambia todos los UserManager a AppUserManager , UserStore a AppUserStore etc. Toma un ejemplo de estos constructores:

 public AccountController() : this( new AppUserManager( new AppUserStore( new AppDbContext() ) ) ) { } public AccountController(AppUserManager userManager) { UserManager = userManager; } 

5. Agregue la identificación del usuario como reclamo de ClaimIdentity almacenado en una cookie

En el paso 1, hemos creado AppClaimsPrincipal , que expone UserId tomado de ClaimType.Sid . Sin embargo, para tener este reclamo disponible, debemos agregarlo, cuando inicie sesión en el usuario. En AccountController un método SingInAsync es responsable de iniciar sesión. Necesitamos agregar una línea a este método para agregar el reclamo.

 private async Task SignInAsync(AppUser user, bool isPersistent) { AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); ClaimsIdentity identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); // Extend identity claims identity.AddClaim( new Claim( ClaimTypes.Sid, user.Id.ToString() ) ); AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); } 

6. Crea un BaseController con una propiedad CurrentUser

Para tener un acceso fácil a la identificación de un usuario actualmente conectado en sus controladores, cree un BaseController abstracto, del cual derivarán sus controladores. En BaseController , crea un CurrentUser siguiente manera:

 public abstract class BaseController : Controller { public AppClaimsPrincipal CurrentUser { get { return new AppClaimsPrincipal( ( ClaimsPrincipal )this.User ); } } public BaseController() { } } 

7. BaseController sus controladores de BaseController y disfrute

A partir de ahora, puede usar CurrentUser.UserId en sus controladores para acceder a una ID de un usuario que CurrentUser.UserId conectado actualmente sin necesidad de realizar viajes a la base de datos. Puede usarlo para consultar únicamente objetos que pertenecen al usuario.

No es necesario que se ocupe de la generación automática de las claves principales del usuario. No es de extrañar que Entity Framework use Identity para las claves primarias enteras al crear tablas.

¡Advertencia! Tenga en cuenta que si lo implementa en un proyecto ya publicado, para los usuarios que ya ClaimsType.Sid sesión, ClaimsType.Sid no existirá y FindFirst devolverá nulo en AppClaimsPrincipal . AppClaimsPrincipal forzar el cierre de sesión de todos los usuarios o manejar este escenario en AppClaimsPrincipal

@HaoKung

He logrado crear identificaciones con tus comstackciones nocturnas. El problema User.Identity.GetUserId () todavía está allí, pero acabo de hacer int.parse () por ahora.

La mayor sorpresa fue que no tuve que crear ID por mi cuenta, db se hizo con identificador de identidad y de alguna manera se configuró automáticamente para nuevos usuarios Oo …

Modelo:

  public class ApplicationUser : IdentityUser { public ApplicationUser() { } public ApplicationUser(string name) : this() { UserName = name; } } public class ApplicationDbContext : IntUserContext { public ApplicationDbContext() { } } private class IntRole : IdentityRole { public IntRole() { } public IntRole(string name) : this() { Name = name; } } private class IntUserRole : IdentityUserRole { } private class IntUserClaim : IdentityUserClaim { } private class IntUserLogin : IdentityUserLogin { } private class IntUserContext : IdentityDbContext { public IntUserContext() : base("DefaultConnection") { } } private class IntUserStore : UserStore { public IntUserStore(DbContext context) : base(context) { } } private class IntRoleStore : RoleStore { public IntRoleStore(DbContext context) : base(context) { } } 

Controlador:

  public AccountController() : this(new UserManager(new IntUserStore(new ApplicationDbContext()))) { } public AccountController(UserManager userManager) { UserManager = userManager; } public UserManager UserManager { get; private set; } 

La versión de lanzamiento de Hope llegará pronto: D …

PD: No puedo escribir comentarios, así que respondí, lo siento.

En Visual Studio 2013, la aplicación web predeterminada usa un valor de cadena para la clave de las cuentas de usuario. ASP.NET Identity le permite cambiar el tipo de clave para cumplir con sus requisitos de datos. Por ejemplo, puede cambiar el tipo de la clave de una cadena a un número entero.

http://www.asp.net/identity/overview/extensibility/change-primary-key-for-users-in-aspnet-identity

Este tema en el enlace de arriba muestra cómo comenzar con la aplicación web predeterminada y cambiar la clave de la cuenta de usuario por un número entero. Puede usar las mismas modificaciones para implementar cualquier tipo de clave en su proyecto. Muestra cómo realizar estos cambios en la aplicación web predeterminada, pero puede aplicar modificaciones similares a una aplicación personalizada. Muestra los cambios necesarios al trabajar con MVC o formularios web.

Básicamente tienes que:

-Cambiar el tipo de la clave a int en la clase de usuario Identity
-Añadir clases de identidad personalizadas que utilizan int como clave
-Cambia la clase de contexto y el administrador de usuarios para usar int como clave
-Cambiar configuración de inicio para usar int como clave
-Cambia el AccountController para pasar int como clave

aquí hay un enlace donde se explican todos los pasos para lograr esto.