0

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;
            }
        }
    }
复制代码

PS:看过源代码了,标记方式针对表名不行,源代码中写死了table name。字段名可以通过标记方式重命名 --by 2016-10-24

3
0
« 上一篇:win8.1 vpn 720错误 解决方法
» 下一篇:asp.net mvc HandleErrorAttribute 异常错误处理 无效!
posted @ 2015-07-15 15:54 czd890 阅读(4884) 评论(8编辑 收藏

  
#1楼 2015-10-07 22:18 phbrother003  
您好,我在创业中,已经拿到投资,游戏产品已经完成,现在在处理游戏细节,等细节处理完成后做上线前的准备。
现在在招人,请问有兴趣加入么,我的QQ55763
  
#2楼 2016-06-22 14:43 Mistletoe1987  
[NullReferenceException: 未将对象引用设置到对象的实例。]
Ninesky.Web.Controllers.<Login>d__11.MoveNext() in F:\webroot\Ninesky.Web\Controllers\AccountController.cs:78
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92

调试出现这个错误,怎么解决啊?
  
#3楼 2016-11-18 13:15 廉毅  
您好啊,我按您的思路做了一下,但

1
2
3
4
5
public Task<LyUser> FindByNameAsync(string userName)
{
    var user = db.LyUser.Where(p => p.emp_id == userName).FirstOrDefaultAsync();
    return user;     //这行报错
}


报这个错误,无法将类型“System.Threading.Tasks.Task<WebApplication1.Models.Pudong.b_employee>”隐式转换为“System.Threading.Tasks.Task<WebApplication1.Models.LyUser>”
请问这个强制类型转换应该怎么写呢?我是初学,实在不会了,希望您指点一下,憋的我挺着急的
  
#4楼[楼主2016-11-18 18:32 czd890  
@ 廉毅
b_employee和LyUser 分别是什么类型。
后面我用的下面这种方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class WXUser : IUser<Guid>
    {
        //User  这个是数据的entity对象
        private User user;
        Guid IUser<Guid>.Id
        {
            get{return user.Id;}
        }
        private WXUser(User user) { this.user = user; }
        string IUser<Guid>.UserName
        {
            get{return user.LoginId;}
            set{user.LoginId = value;}
        }
        public static implicit operator WXUser(User user)
        {
            return new WXUser(user);
        }
        public static implicit operator User(WXUser user)
        {
            return user.user;
        }

转自:http://www.cnblogs.com/calvinK/p/4648138.html
关闭 返回顶部
联系我们
Copyright © 2011. 聚财吧. All rights reserved.