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;
            }
        }
    }
时间: 2024-08-27 18:56:13

Microsoft.AspNet.Identity 自定义使用现有的表—登录实现的相关文章

Asp.net Identity 系列之 怎样修改Microsoft.AspNet.Identity.EntityFramework.IdentityUser 的 Id 字段的数据类型

这篇博客我们来学习如何将AspNetUsers 表的Id 字段 的类型由nvarchar(128) 改为Int 并且子增长 1.为什么要修改 如果你运行过 Asp.net mvc 示例项目,你好会发现 AspNetUsers 表的Id是Nvarchar(128) 类型,值为GUID,不可否认使用GUID来做主键进行主外键关联会增加数据安全性(个人看法),但是非常不利于查询,可读性不够,因此我们尝试着去改为Int类型. 先看一下修改后的效果: 2.修改前分析 查看数据库结构我们知道要修改的表有这样

从Microsoft.AspNet.Identity看微软推荐的一种MVC的分层架构

Microsoft.AspNet.Identity简介 Microsoft.AspNet.Identity是微软在MVC 5.0中新引入的一种membership框架,和之前ASP.NET传统的membership以及WebPage所带来的SimpleMembership(在MVC 4中使用)都有所不同. Microsoft.AspNet.Identity是符合微软开放Owin标准里面Security标准的一种实现.且在MVC 5中默认使用EntityFramework作为Microsoft.A

Microsoft.AspNet.Identity 2.0 用账号或者邮件作为登陆方式

创建一个默认的MVC4.0的项目工程,默认的登陆方式是邮件登陆,那么有没办法改为用账号登陆? 我们来看下默认的登陆Action [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return View(model); }// This doesn

Microsoft.AspNet.Identity.EntityFramework/IdentityDbContext.cs

using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Common; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.Entity.Infrastructure.Annotations; usin

Microsoft.AspNet.Identity 重置密码

原文:Microsoft.AspNet.Identity 重置密码 重置密码:先生成重置密码的Token,然后调用ResetPassword方法重置密码,密码要符合规则.. ApplicationUserManager UserManager => _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>(); string token = UserManager.Generat

Microsoft.AspNet.Identity: UserID用整型数据表示, 而不是GUID

http://stackoverflow.com/questions/19553424/how-to-change-type-of-id-in-microsoft-aspnet-identity-entityframework-identityus

Microsoft.Aspnet.Snapin 命名空间

  The Microsoft.Aspnet.Snapin namespace defines the types necessary for the ASP.NET management console application to interact with Microsoft Management Console (MMC). For more information, see "MMC Programmer's Guide" in the   MSDN Library.   

AspNet Identity and IoC Container Registration

https://github.com/trailmax/IoCIdentitySample TL;DR: Registration code for Autofac, for SimpleInjector, for Unity. Tony Mackay has an alternative walk-through of a very similar process but with Autofac Part 2: Sending Emails in Asp.Net Identity using

Webform中启用Microsoft.AspNet.FriendlyUrls引起post请求失效

开启 Microsoft.AspNet.FriendlyUrls之后,POST请求转为Get请求,且使表单丢失 目前没有找到解决方案