如何在Microsoft.AspNet.Identity.EntityFramework.IdentityUser中更改id的types

(ASP.NET MVC 5,EF6,VS2013)

我试图找出如何更改types的string中的“Id”字段的types为int

Microsoft.AspNet.Identity.EntityFramework.IdentityUser 

为了让新的用户帐户与一个整数ID而不是一个GUID相关联。 但是,似乎这将比在我的派生用户类中简单地添加一个带有inttypes的新的Id属性更为复杂。 看看这个方法签名:

(从程序集Microsoft.AspNet.Identity.Core.dll)

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

所以,似乎还有其他的方法被烘焙到ASP.NET身份框架中,要求userId是一个string。 我是否还需要重新实现这些类?

解释为什么我不想在用户表中存储ID的GUID:

– 将有其他表格通过外键将数据与用户表相关联。 (当用户在网站上保存内容。)我没有理由使用更大的字段types,并花费额外的数据库空间没有明显的优势。 (我知道还有其他一些关于使用GUID和int ID的post,但是似乎很多人认为int id更快,占用空间更less,这仍然让我感到疑惑。

我计划公开一个平静的端点,允许用户检索有关特定用户的数据。 我认为:

 /users/123/name 

比…更清洁

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

有谁知道为什么ASP.NET团队决定以这种方式实现ID? 我试图将其更改为inttypes,目光短浅吗? (也许我错过了好处。)

谢谢…

-ben

所以如果你想要int id,你需要创build你自己的POCO IUser类,并在1.0 RTM版本中为你自定义的IUser类实现你的IUserStore。

这是我们没有时间去支持的事情,但是我现在正在考虑让这个更简单(更简单)。 希望在即将build成的夜晚有东西可用。

更新1.1-alpha1例子: 如何获得每晚builts

如果你更新到最新的每晚,你可以尝试新的1.1-alpha1 apis,这应该使现在更容易:这是什么插入guids而不是string应该看起来像例如

  public class GuidRole : IdentityRole<Guid, GuidUserRole> { public GuidRole() { Id = Guid.NewGuid(); } public GuidRole(string name) : this() { Name = name; } } public class GuidUserRole : IdentityUserRole<Guid> { } public class GuidUserClaim : IdentityUserClaim<Guid> { } public class GuidUserLogin : IdentityUserLogin<Guid> { } public class GuidUser : IdentityUser<Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> { public GuidUser() { Id = Guid.NewGuid(); } public GuidUser(string name) : this() { UserName = name; } } private class GuidUserContext : IdentityDbContext<GuidUser, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> { } private class GuidUserStore : UserStore<GuidUser, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> { public GuidUserStore(DbContext context) : base(context) { } } private class GuidRoleStore : RoleStore<GuidRole, Guid, GuidUserRole> { public GuidRoleStore(DbContext context) : base(context) { } } [TestMethod] public async Task CustomUserGuidKeyTest() { var manager = new UserManager<GuidUser, Guid>(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); } } 

使用Stefan Cebulak的答案和Ben Foster出色的博客文章ASP.NET Identity Stripped Bare,我想出了下面的解决scheme,我已经将这个解决scheme应用到ASP.NET Identity 2.0中 ,由Visual Studio 2013 AccountController生成。

该解决scheme使用一个整数作为用户的主键,并且还允许获取当前login用户的ID而不需要去数据库。

这里是步骤,你需要遵循:

1.创build自定义用户相关的类

默认情况下, AccountController使用正在使用string的类作为主键的types。 我们需要创build下面的类,它将使用int来代替。 我已经在一个文件中定义了所有下面的类: AppUser.cs

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

拥有一个自定义的ClaimsPrincipal也很有用,它将很容易地暴露用户的ID

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

2.创build一个自定义IdentityDbContext

我们的应用程序的数据库上下文将扩展IdentityDbContext ,它默认实现所有与authentication有关的DbSets。 即使DbContext.OnModelCreating是一个空方法,我不确定IdentityDbContext.OnModelCreating ,所以当重写时,记得调用base.OnModelCreating( modelBuilder ) AppDbContext.cs

 public class AppDbContext : IdentityDbContext<AppUser, AppRole, int, AppUserLogin, AppUserRole, AppUserClaim> { public AppDbContext() : base("DefaultConnection") { // Here use initializer of your choice Database.SetInitializer( new CreateDatabaseIfNotExists<AppDbContext>() ); } // 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.创build自定义UserStoreUserManager ,这将在上面使用

AppUserStore.cs

 public interface IAppUserStore : IUserStore<AppUser, int> { } public class AppUserStore : UserStore<AppUser, AppRole, int, AppUserLogin, AppUserRole, AppUserClaim>, IAppUserStore { public AppUserStore() : base( new AppDbContext() ) { } public AppUserStore(AppDbContext context) : base(context) { } } 

AppUserManager.cs

 public class AppUserManager : UserManager<AppUser, int> { public AppUserManager( IAppUserStore store ) : base( store ) { } } 

4.修改AccountController以使用您的自定义类

将所有UserManager更改为AppUserManager ,将AppUserStore更改为AppUserStore等。以此构造函数为例:

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

5.将用户ID作为索赔添加到存储在cookie中的ClaimIdentity

在第1步中,我们创build了AppClaimsPrincipal ,它公开从ClaimType.Sid中取出的ClaimType.Sid 。 但是,要获得此声明,我们需要在login用户时添加它。 在AccountController一个SingInAsync方法负责login。我们需要在这个方法中添加一行来添加索赔。

 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.使用CurrentUser属性创build一个BaseController

要在控制器中轻松访问当前login的用户ID,请创build一个抽象的BaseController ,控制器将从其中导出。 在BaseController ,按如下所示创build一个CurrentUser

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

7.从BaseControllerinheritance你的控制器,并享受

从现在开始,您可以在您的控制器中使用CurrentUser.UserId来访问当前login用户的ID,而不需要访问数据库。 您可以使用它来查询属于该用户的对象。

您不必关心用户主键的自动生成 – 毫不奇怪,在创build表时,Entity Framework默认使用Identity作为整数主键。

警告! 请记住,如果您在已经发布的项目中实现它,对于已经login的用户, ClaimsType.Sid将不存在,并且FindFirst将在AppClaimsPrincipal返回null。 您需要强制注销所有用户或在AppClaimsPrincipal处理这种情况

@HaoKung

我已经成功地用你的每晚构buildint id了。 User.Identity.GetUserId()问题仍然存在,但我现在只是int.parse()。

最大的惊喜是,我不需要自己创buildID,数据库是用身份证制作的,它以某种方式自动设置为新用户O …

模型:

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

控制器:

  public AccountController() : this(new UserManager<ApplicationUser, int>(new IntUserStore(new ApplicationDbContext()))) { } public AccountController(UserManager<ApplicationUser, int> userManager) { UserManager = userManager; } public UserManager<ApplicationUser, int> UserManager { get; private set; } 

希望发布版本即将推出:D …

PS不能写评论,所以我做了一个答案,对不起。

在Visual Studio 2013中,默认Web应用程序为用户帐户的密钥使用string值。 ASP.NET Identity使您能够更改密钥的types以满足您的数据要求。 例如,您可以将键的types从一个string更改为一个整数。

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

以上链接中的主题显示了如何从默认的Web应用程序启动并将用户帐户密钥更改为整数。 您可以使用相同的修改来实现项目中的任何types的键。 它显示了如何在默认的Web应用程序中进行这些更改,但是可以对定制的应用程序应用类似的修改。 它显示了使用MVC或Web窗体时所需的更改。

基本上你必须:

– 在Identity用户类中将密钥的types更改为int
– 添加使用int作为键的自定义标识类
– 更改上下文类和用户pipe理器以使用int作为键
– 将启动configuration更改为使用int作为键
– 更改AccountController以传递int作为键

这里是链接,所有的步骤解释,以实现这一目标。

如果您使用ASP .Net Identity 3.0(testing版6),则有一个非常直接的解决scheme,但我努力在网上find任何文档。 经过一些试验和错误,我发现了一个很好的简单的解决scheme,并在这里博客: http : //mycodelog.com/2015/08/18/asp-net-vnext-identity-3-0-beta6-in-mvc-6 -beta6-SPA-使用整数密钥-代替-的串/