你的位置:首页 > ASP.net教程

[ASP.net教程]Microsoft.AspNet.Identity 自定义使用现有的表—登录实现


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框架中的代码为

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的源代码实现对应的接口即可.

1.FindByNameAsync 先根据登录名找到user对象,使用UserManager中的UserStroe所实现IUserStore的接口方法

2.IsLockedOutAsync 检查登录是否锁定,使用UserManager中的UserStroe所实现的IUserLockoutStore接口方法

3.CheckPasswordAsync 检查密码,使用UserManager中的UserStroe所实现的IUserPasswordStore接口方法

4.ResetAccessFailedCountAsync 登录成功,重置登录失败计数,使用UserManager中的UserStroe所实现的IUserLockoutStore接口方法

5.SignInOrTwoFactor 双重身份验证,使用UserManager中的UserStroe所实现的IUserTwoFactorStore接口方法

 

SignInManager是入口,需要用到UserManager,UserManager需要用到关键的UserStore,具体的框架的介绍可以参考园子里其他的文章,都讲的很好,并且很好的讲明了为何需要这么设计。

实现

已有资源,假如我们已经有了数据库,有了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;      }    }  }




江西旅游住哪里比较方便江西旅游住宿攻略江西旅游最佳时间江西自驾游最佳路线江西旅游多少钱2015清明节田野绿世界门票多少钱?佛冈田野绿世界清明节门票价格? 佛冈田野绿世界清明节有什么花开?田野绿世界清明节赏花攻略? 看看那些制造话题的复活蛋[三] 佛冈田野绿世界柚子花开了吗?田野绿世界柚子花开花时间? 高明油菜花能开多长时间?2015高明油菜花最佳观赏时间? 2015高明油菜花节几号到几号?高明油菜花节具体时间及票价? 高明油菜花什么时候开?2015高明油菜花开多长时间? 高明盈香生态园油菜花开了吗?高明油菜花开花时间? 大连叶太美 寻找金秋美景微旅行 深秋杏正浓 寻沈阳最美金色画面 候鸟始飞白露至 在无锡要做的几件事 中国竹乡安吉秋冬季深度游新鲜玩法(组图) 香港迪士尼在哪里?香港迪士尼乐园怎么去 香港海洋公园好玩吗? 香港迪士尼乐园旅游攻略? 澳门环岛游好玩吗?珠海澳门环岛游怎么样? AQ12EA680JAJME\250 Datasheet AQ12EA680JAJME\250 Datasheet 08055U120FAT9A Datasheet 08055U120FAT9A Datasheet SQCAEA100GAJME Datasheet SQCAEA100GAJME Datasheet 到牡丹江跟团去香港旅游 到牡丹江跟团去香港旅游 到牡丹江跟团去香港旅游 佳木斯去香港旅游 佳木斯去香港旅游 佳木斯去香港旅游 福州去香港旅游 福州去香港旅游 福州去香港旅游