Microsoft.AspNet.Identity是微软新引入的一种membership框架,也是微软Owin标准的一个实现。Microsoft.AspNet.Identity.EntityFramework则是Microsoft.AspNet.Identity的数据提供实现。可是在使用此框架的时候存在一些问题,若是是全新的项目还可使用它默认提供的表名,字段名等。可是若是是在一些老的数据库上应用这个框架就比较麻烦了。因此咱们实现一个本身的Microsoft.AspNet.Identity.EntityFramework数据库
首先咱们只说登陆,登陆的入口代码是框架
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
对应Owin框架中的代码为async
public virtual async Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout) { SignInStatus result; if (this.UserManager == null) { result = SignInStatus.Failure; } else { TUser tUser = await this.UserManager.FindByNameAsync(userName).WithCurrentCulture<TUser>(); if (tUser == null) { result = SignInStatus.Failure; } else if (await this.UserManager.IsLockedOutAsync(tUser.Id).WithCurrentCulture<bool>()) { result = SignInStatus.LockedOut; } else if (await this.UserManager.CheckPasswordAsync(tUser, password).WithCurrentCulture<bool>()) { await this.UserManager.ResetAccessFailedCountAsync(tUser.Id).WithCurrentCulture<IdentityResult>(); result = await this.SignInOrTwoFactor(tUser, isPersistent).WithCurrentCulture<SignInStatus>(); } else { if (shouldLockout) { await this.UserManager.AccessFailedAsync(tUser.Id).WithCurrentCulture<IdentityResult>(); if (await this.UserManager.IsLockedOutAsync(tUser.Id).WithCurrentCulture<bool>()) { result = SignInStatus.LockedOut; return result; } } result = SignInStatus.Failure; } } return result; }
由此代码可大概知晓登陆的流程是,固然还有登陆失败的流程就先不实现了。须要实现也很是简单,根据Owin的源代码实现对应的接口便可.ide
1.FindByNameAsync 先根据登陆名找到user对象,使用UserManager中的UserStroe所实现IUserStore的接口方法ui
2.IsLockedOutAsync 检查登陆是否锁定,使用UserManager中的UserStroe所实现的IUserLockoutStore接口方法this
3.CheckPasswordAsync 检查密码,使用UserManager中的UserStroe所实现的IUserPasswordStore接口方法spa
4.ResetAccessFailedCountAsync 登陆成功,重置登陆失败计数,使用UserManager中的UserStroe所实现的IUserLockoutStore接口方法.net
5.SignInOrTwoFactor 双重身份验证,使用UserManager中的UserStroe所实现的IUserTwoFactorStore接口方法设计
SignInManager是入口,须要用到UserManager,UserManager须要用到关键的UserStore,具体的框架的介绍能够参考园子里其余的文章,都讲的很好,而且很好的讲明了为什么须要这么设计。code
已有资源,假如咱们已经有了数据库,有了user表,有了id字段guid类型,有了loginid表明登陆的用户名,也就是源代码中的username
第一步 先实现咱们本身的SignInManager,继承自Microsoft.AspNet.Identity.Owin.SignInManager<TUser, TKey>
public class WXSignInManager : SignInManager<WXUser, Guid> { public WXSignInManager(UserManager<WXUser, Guid> userManager, IAuthenticationManager authenticationManager) : base(userManager, authenticationManager) { } public static WXSignInManager Create(IdentityFactoryOptions<WXSignInManager> options, IOwinContext context) { return new WXSignInManager(context.GetUserManager<WXUserManager>(), context.Authentication); }
咱们的SignInManager代码中有一行context.GetUserManager<WXUserManager>(),因此继续实现咱们的UserManager。
第二步 实现咱们的本身的UserManager,继承自Microsoft.AspNet.Identity.UserManager<TUser, TKey>
public class WXUserManager : UserManager<WXUser, Guid> { public WXUserManager(IUserStore<WXUser, Guid> store) : base(store) { } public static WXUserManager Create(IdentityFactoryOptions<WXUserManager> options, IOwinContext context) { return new WXUserManager(new WXUserStore(context.Get<WXDBContexnt>())) { PasswordHasher = new MyPasswordHasher() }; } }
由以前Owin源代码能够知道重点代码都在UserStore中,接下来
第三步,实现咱们本身的UserStore,分别实现接口
Microsoft.AspNet.Identity.IUserStore<TUser, in TKey>,//数据库访问相关接口
Microsoft.AspNet.Identity.IUserLockoutStore<TUser, in TKey>,//用户锁定,登陆失败计数相关接口
Microsoft.AspNet.Identity.IUserPasswordStore<TUser, in TKey>,//用户密码相关接口
Microsoft.AspNet.Identity,IUserTwoFactorStore<TUser, in TKey>//双重身份验证相关接口
public class WXUserStore : IUserStore<WXUser, Guid>, IUserLockoutStore<WXUser, Guid>, IUserPasswordStore<WXUser, Guid>, IUserTwoFactorStore<WXUser, Guid> { public WXUserStore(WXDBContexnt dbContext) { this.dbContext = dbContext; } WXDBContexnt dbContext; public async Task<WXUser> FindByIdAsync(Guid userId) { var user = await dbContext.WXUser.FindAsync(userId); return user; } public async Task<WXUser> FindByNameAsync(string userName) { return dbContext.WXUser.Where(p => p.LoginId == userName).FirstOrDefaultAsync(); } public Task ResetAccessFailedCountAsync(WXUser user) { return Task.FromResult(false); } public Task<bool> GetLockoutEnabledAsync(WXUser user) { return Task.FromResult(false); } public Task<string> GetPasswordHashAsync(WXUser user) { return Task.FromResult(user.LoginPWD); } public Task<bool> GetTwoFactorEnabledAsync(WXUser user) { return Task.FromResult(false); } }
这里仅仅是完成一个超级简单的登陆功能,因此无关的实现都删除了,须要注意的是p => p.LoginId == userName,原有数据库中登陆名的字段是loginId。接口的意思能够查看文档便可,相信从方法的名字就能猜到具体的意思,人家设计的接口就是好<!_!>。
我这里使用的是EF做为数据提供源,固然你也可使用本身的,只须要替换FindByIdAsync,FindByNameAsync方法中对应的实现,哪怕是在这些方面里面使用ado.net直接查询数据都是彻底没有问题的。wxuser我继承了系统已经存在的user对象,而后强类型实现了IUser接口,由于我原系统对象已存在了username属性。而此处的wxuser.username属性是做为用户登陆的帐号意思存在的。因此我强类型实现。
public class WXUser : 系统已存在的user entity对象, IUser<Guid> { Guid IUser<Guid>.Id { get { return this.Id; } } string IUser<Guid>.UserName { get { return this.LoginId; } set { this.LoginId = value; } } } public class WXDBContexnt : DbContext { public WXDBContexnt() { } public static WXDBContexnt Create() { return new WXDBContexnt(); } public DbSet<WXUser> WXUser { get; set; } }
大体代码就是如此了,固然咱们本身实现的UserStore对象还有不少方法没有实现,but我只是须要一个登陆不是么,能够慢慢改造的嘛<!_!>
写到最后想到经过重写的方式估计也能实现,这是新建项目生成的默认代码,为何不能够增长[Table("Users")],[Column("LoginId")],override达到效果呢。
[Table("Users")] public class ApplicationUser : IdentityUser { public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager) { // 请注意,authenticationType 必须与 CookieAuthenticationOptions.AuthenticationType 中定义的相应项匹配 var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); // 在此处添加自定义用户声明 return userIdentity; } [Column("LoginId")] public override string UserName { get { return base.UserName; } set { base.UserName = value; } } }
PS:看过源代码了,标记方式针对表名不行,源代码中写死了table name。字段名能够经过标记方式重命名 --by 2016-10-24