Как изменить тип идентификатора в Microsoft.AspNet.Identity.EntityFramework.IdentityUser

(ASP.NET MVC 5, EF6, VS2013)

Я пытаюсь выяснить, как изменить тип поля «Id» от строки до int в типе:

Microsoft.AspNet.Identity.EntityFramework.IdentityUser 

чтобы новые учетные записи пользователей были связаны с идентификатором целого числа, а не с идентификатором GUID. Но похоже, что это будет сложнее, чем просто добавить новое свойство Id с типом int в моем производном classе пользователя. Взгляните на эту подпись метода:

(из сборки Microsoft.AspNet.Identity.Core.dll)

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

Таким образом, кажется, что есть другие методы, запеченные в структуре идентификации ASP.NET, которые требуют, чтобы userId был строкой. Нужно ли мне переопределять эти classы?

Объяснение того, почему я не хочу хранить идентификаторы GUID для идентификаторов в таблице пользователя:

– Будут другие таблицы, которые связывают данные с таблицей пользователей через внешний ключ. (Когда пользователи сохраняют контент на сайте.) Я не вижу причин использовать более широкий тип поля и тратить дополнительное пространство базы данных без явных преимуществ. (Я знаю, что есть другие сообщения об использовании GUID vs int ids, но кажется, что многие считают, что int ids быстрее и используют меньше места, что все еще оставляет мне интересно.)

-Я планирую выставить спокойную конечную точку, чтобы пользователи могли получать данные о конкретном пользователе. Я думаю:

 /users/123/name 

чище, чем

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

Кто-нибудь знает, почему команда ASP.NET решила реализовать идентификаторы таким образом? Я не подозреваю, что пытаюсь изменить это на тип int? (Возможно, есть льготы, которые мне не хватает.)

Благодаря…

-Бен

Поэтому, если вы хотите установить идентификаторы, вам нужно создать свой собственный class POCO IUser и реализовать свой IUserStore для вашего пользовательского classа IUser в версии RTM версии 1.0.

Это то, что у нас не было времени для поддержки, но сейчас я изучаю это легко (ier) в 1.1. Надеюсь, что кое-что будет доступно в ночных assemblyх в ближайшее время.

Обновлено с примером 1.1-alpha1: Как получить ночные постройки

Если вы обновляетесь до последних ночных бит, вы можете попробовать новый 1.1-alpha1 apis, который должен сделать это проще сейчас: вот что такое включение гидов вместо строк должно выглядеть, например,

  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); } } 

Используя ответ Стефана Кебулака и замечательную статью блога Бена Фостера, ASP.NET Identity Stripped Bare, я придумал ниже решение, которое я применил к ASP.NET Identity 2.0 с помощью Visual AccountController 2013 AccountController .

Решение использует целое число как первичный ключ для пользователей, а также позволяет получить идентификатор текущего пользователя, не совершая поездки в базу данных.

Вот шаги, которые вам нужно выполнить:

1. Создайте пользовательские classы, связанные с пользователем.

По умолчанию AccountController использует classы, которые используют string , в качестве типа первичного ключа. Нам нужно создать classы ниже, которые будут использовать вместо int . Я определил все classы ниже в одном файле: AppUser.cs

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

Также будет полезно, чтобы пользовательский ClaimsPrincipal, который будет легко выставлять идентификатор пользователя

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

2. Создайте собственный IdentityDbContext

Контекст базы данных нашего приложения будет расширять IdentityDbContext , который по умолчанию реализует все DbSets, связанные с аутентификацией. Даже если DbContext.OnModelCreating – пустой метод, я не уверен в IdentityDbContext.OnModelCreating , поэтому при переопределении не забудьте вызвать 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. Создайте пользовательский UserStore и UserManager , который будет использоваться выше

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. Измените AccountController для использования ваших пользовательских classов.

Измените все UserManager на AppUserManager , UserStore на AppUserStore и т. Д. Возьмите пример этих конструкторов:

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

5. Добавьте идентификатор пользователя в качестве требования к ClaimIdentity хранящемуся в файле cookie

На шаге 1 мы создали AppClaimsPrincipal , который предоставляет UserId, взятый из ClaimType.Sid . Однако, чтобы иметь эту претензию, нам нужно добавить ее при регистрации в пользователе. В AccountController для входа в систему SingInAsync метод SingInAsync . Нам нужно добавить строку к этому методу, чтобы добавить заявку.

 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. Создайте BaseController с свойством CurrentUser

Чтобы иметь легкий доступ к уже зарегистрированному идентификатору пользователя в ваших controllerах, создайте абстрактный BaseController , из которого будут выводиться ваши controllerы. В BaseController создайте CurrentUser следующим образом:

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

7. BaseController controllerы от BaseController и наслаждайтесь

С этого CurrentUser.UserId вы можете использовать CurrentUser.UserId в своих controllerах для доступа к идентификатору текущего пользователя, не подключенного к базе данных. Вы можете использовать его для запроса только объектов, принадлежащих пользователю.

Вам не нужно заботиться об автоматическом создании первичных ключей пользователя – не удивительно, что Entity Framework по умолчанию использует Identity для целых первичных ключей при создании таблиц.

Предупреждение! Имейте в виду, что если вы реализуете его в уже выпущенном проекте, для уже зарегистрированных пользователей ClaimsType.Sid не будет существовать, и FindFirst вернет null в AppClaimsPrincipal . Вам нужно либо принудительно вывести всех пользователей, либо AppClaimsPrincipal этот сценарий в AppClaimsPrincipal

@HaoKung

Мне удалось сделать int id с вашими ночными assemblyми. Проблема User.Identity.GetUserId () все еще существует, но я только что сделал int.parse ().

Самым большим сюрпризом было то, что мне не нужно было создавать ID самостоятельно, db был создан с идентификатором идентификатора, и он был как-то автоматически установлен для новых пользователей Oo …

Модель:

  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) { } } 

controller:

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

Скоро появится assembly Hope: D …

PS Не могу писать комментарии, поэтому я сделал ответ, извините.

В Visual Studio 2013 веб-приложение по умолчанию использует строковое значение для ключа для учетных записей пользователей. Идентификатор ASP.NET позволяет вам изменить тип ключа для соответствия вашим требованиям к данным. Например, вы можете изменить тип ключа из строки в целое.

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

В этом разделе приведенной выше ссылки показано, как начать с веб-приложения по умолчанию и изменить ключ учетной записи пользователя на целое. Вы можете использовать те же самые модификации для реализации любого типа ключа в вашем проекте. Он показывает, как внести эти изменения в веб-приложение по умолчанию, но вы можете применить аналогичные изменения к настраиваемому приложению. Он показывает изменения, необходимые при работе с MVC или веб-формами.

В основном вы должны:

-Измените тип ключа для int в пользовательском classе Identity
-Добавить настраиваемые classы идентификаторов, которые используют int как ключ
-Измените class контекста и пользовательский менеджер, чтобы использовать int как ключ
-Установить конфигурацию запуска, чтобы использовать int как ключ
-Измените AccountController для передачи int как ключа

здесь ссылка, где все шаги объясняются для достижения этого.

  • Как вы входите в систему / аутентифицируете пользователя с битами Asp.Net MVC5 RTM с использованием AspNet.Identity?
  • Хостинг WebAPI с использованием OWIN в службе Windows
  • OWIN's GetExternalLoginInfoAsync всегда возвращает null
  • Как получить доступ к личной информации Facebook, используя идентификатор ASP.NET (OWIN)?
  • Идентификация ASP.NET (OWIN): как получить UserID с controllerа веб-API?
  • Нужен ли мне файл Global.asax.cs вообще, если я использую class OWIN Startup.cs и перемещаю туда всю конфигурацию?
  • Давайте будем гением компьютера.