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