如何在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自定义UserStore
和UserManager
,这将在上面使用
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.从BaseController
inheritance你的控制器,并享受
从现在开始,您可以在您的控制器中使用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-使用整数密钥-代替-的串/