使用Stefan Cebulak的回答和 Ben Foster 的精彩博客文章ASP.NET Identity Stripped Bare我想出了以下解决方案,我已将其应用于 ASP.NET Identity 2.0并由 Visual Studio 2013 生成AccountController
。
该解决方案使用整数作为用户的主键,还允许在不访问数据库的情况下获取当前登录用户的 ID。
以下是您需要遵循的步骤:
1.创建自定义用户相关类
默认情况下,AccountController
使用的类string
作为主键类型。我们需要创建下面的类,它将使用 anint
来代替。我在一个文件中定义了以下所有类: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")
{
// 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
and 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
存储在 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);
// Extend identity claims
identity.AddClaim( new Claim( ClaimTypes.Sid, user.Id.ToString() ) );
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
BaseController
6.用CurrentUser
属性创建一个
要在您的控制器中轻松访问当前登录的用户 ID,请创建一个 abstract BaseController
,您的控制器将从中派生。在 中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
将在AppClaimsPrincipal
. 您需要强制注销所有用户或在AppClaimsPrincipal