通过使用Stefan Cebulak的答案和Ben Foster的精彩博客文章ASP.NET Identity Striped Bare,我提出了以下解决方案,该解决方案已应用于Visual Studio 2013生成的ASP.NET Identity 2.0AccountController
。
该解决方案使用整数作为用户的主键,还允许在不访问数据库的情况下获取当前登录用户的ID。
这是步骤,您需要遵循:
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
,默认情况下实现所有与身份验证相关的DbSet。即使DbContext.OnModelCreating
是空方法,我也不确定IdentityDbContext.OnModelCreating
,所以在覆盖时,请记住调用base.OnModelCreating( modelBuilder )
AppDbContext.cs
public class AppDbContext :
IdentityDbContext<AppUser, AppRole, int, AppUserLogin, AppUserRole, AppUserClaim>
{
public AppDbContext() : base("DefaultConnection")
{
Database.SetInitializer( new CreateDatabaseIfNotExists<AppDbContext>() );
}
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
base.OnModelCreating( modelBuilder );
}
}
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
etc。以以下构造函数为例:
public AccountController()
: this( new AppUserManager( new AppUserStore( new AppDbContext() ) ) )
{
}
public AccountController(AppUserManager userManager)
{
UserManager = userManager;
}
5.添加用户ID作为声明ClaimIdentity
存储在cookie中
在步骤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);
identity.AddClaim( new Claim( ClaimTypes.Sid, user.Id.ToString() ) );
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
6.创建一个BaseController
带有CurrentUser
属性的
要轻松访问控制器中当前登录的用户ID,请创建一个abstract BaseController
,您的控制器将从中提取该ID 。在中BaseController
,创建CurrentUser
如下:
public abstract class BaseController : Controller
{
public AppClaimsPrincipal CurrentUser
{
get { return new AppClaimsPrincipal( ( ClaimsPrincipal )this.User ); }
}
public BaseController()
{
}
}
7.继承您的控制器BaseController
并享受
从现在开始,您可以CurrentUser.UserId
在控制器中使用来访问当前登录用户的ID,而无需访问数据库。您可以使用它来仅查询属于用户的对象。
您不必照顾用户主键的自动生成-毫不奇怪,在创建表时,默认情况下,Entity Framework使用Identity作为整数主键。
警告!请记住,如果在已发布的项目中实现它,则对于已经登录的用户ClaimsType.Sid
将不存在,并且在FindFirst
中将返回null AppClaimsPrincipal
。您需要强制注销所有用户或处理以下情况:AppClaimsPrincipal