Използвайки отговора на Stefan Cebulak и страхотната статия в блога на Ben Foster ASP.NET Identity Stripped Bare Измислих решение по-долу, което приложих към ASP .NET идентичност 2.0 с генериран от Visual Studio 2013 AccountController
.
Решението използва цяло число като първичен ключ за потребителите и също така позволява да се получи идентификационен номер на влезлия в момента потребител, без да се прави пътуване до базата данни.
Ето стъпките, които трябва да следвате:
1. Създайте персонализирани класове, свързани с потребителя
По подразбиране AccountController
използва класове, които използват string
, като тип първичен ключ. Трябва да създадем класове по-долу, които ще използват 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. Създайте персонализиран IdentityDbContext
Контекстът на базата данни на нашето приложение ще разшири IdentityDbContext
, който прилага по подразбиране всички 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. Създайте персонализирани 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
, UserStore
на AppUserStore
и т.н. Вземете пример за този конструктор:
public AccountController()
: this( new AppUserManager( new AppUserStore( new AppDbContext() ) ) )
{
}
public AccountController(AppUserManager userManager)
{
UserManager = userManager;
}
5. Добавете ID на потребителя като иск към ClaimIdentity
, съхранен в бисквитка
В стъпка 1 създадохме AppClaimsPrincipal
, което показва UserId, взет от ClaimType.Sid
. Въпреки това, за да имаме това твърдение налично, трябва да го добавим, когато влизаме като потребител. В AccountController
метод 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
За да имате лесен достъп до идентификационен номер на влязъл в момента потребител във вашите контролери, създайте абстракт BaseController
, от който вашите контролери ще произлизат. В BaseController
създайте CurrentUser
както следва:
public abstract class BaseController : Controller
{
public AppClaimsPrincipal CurrentUser
{
get { return new AppClaimsPrincipal( ( ClaimsPrincipal )this.User ); }
}
public BaseController()
{
}
}
7. Наследете вашите контролери от BaseController
и се наслаждавайте
Отсега нататък можете да използвате CurrentUser.UserId
във вашите контролери за достъп до идентификатор на текущо влязъл потребител без пътувания до базата данни. Можете да го използвате, за да търсите само обекти, които принадлежат на потребителя.
Не е нужно да се грижите за автоматично генериране на потребителски първични ключове - не е изненада, Entity Framework по подразбиране използва идентичност за целочислени първични ключове, когато създава таблици.
Предупреждение! Имайте предвид, че ако го внедрите във вече издаден проект, за вече влезли потребители ClaimsType.Sid
няма да съществува и FindFirst
ще върне null в AppClaimsPrincipal
. Трябва или да принудите да излезете от всички потребители, или да се справите с този сценарий в AppClaimsPrincipal
person
krzychu
schedule
09.05.2014