在前一篇文章已经为大家介绍了OWIN和Katana,有了对他们的了解之后,才能更好地去学习Asp.net Identity,因为Asp.net Identity的实现集成了Owin。其实在Asp.net 2.0的时候,微软已经对用户权限管理进行了实现,其实现为Membership。由于之前的实现有很多限制,所以微软在Asp.net 4.5推出了Asp.net Identity。接下来,本篇文章将详细介绍下Asp.net Identity的实现。
在前面我们已经说过,在Asp.net 2.0的时候,Asp.net中就已经实现了用户权限管理,所以,Asp.net 用户权限管理有其发展历程。下图就是Asp.net中权限管理的发展历程:
ASP.NET Membership
Asp.net Membership是在2005年的Asp.net 2.0引入的。Membership机制引入了表单验证(Form Authentication),以及一个用于存储用户名、密码和其他用户信息的SQL Server数据库。但它同样存在一些限制:
Asp.net Simple Membership是对Asp.net Membership的一次改进,它使得你可以更容易自定义用户信息。尽管如此,由于它依然是基于Asp.net Membership之上的,所以它仍然存在以下几点限制:
Asp.net Universal Providers解决了前两者的一些问题,例如他支持存储用户在Azure SQL和SQL Server Compact数据库中。并且它基于EF code First实现的,所以它支持EF支持的所有数据库。但由于它依然是基于Asp.net Membreship基础架构实现的,所以仍然有些问题不能很好解决。所以它只解决了前两者的部分问题,其本身还存在一些限制:
随着互联网的快速发展,从而非关系数据库也层出不穷,但之前的三者权限管理都对非关系数据库支持的不是很好,所以微软必须要实现一种新的权限管理机制,所以在。NET Framework中推出了Asp.net Identity。该套机制解决了之前的所有问题。Asp.net 具有如下特点:
从上面对Asp.net Identity的介绍可以发现,它确实解决了之前的所有问题,那它是如何做到的呢?要知道其实现机制并不难,因为Asp.net Identity已经开源,我们可以到其站点下载其源码研究即可,其开源地址为:http://aspnetidentity.codeplex.com/。这里简单的分析它注册和登录的功能的内部实现。
首先使用VS2013创建一个Asp.net MVC站点,此时网站的用户授权和认证模块的代码的实现VS已经帮我们添加好了,我们只需要找到对应的注册和登录功能对其进行分析,从而明白Asp.net Identity是如何帮完成这两个功能的。
首先,我们找到Accout控制器中注册功能的实现代码:
public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false); // 有关如何启用帐户确认和密码重置的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=320771 // 发送包含此链接的电子邮件 // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); // await UserManager.SendEmailAsync(user.Id, "确认你的帐户", "请通过单击 <a href=\"" + callbackUrl + "\">這裏</a>来确认你的帐户"); return RedirectToAction("Index", "Home"); } AddErrors(result); } // 如果我们进行到这一步时某个地方出错,则重新显示表单 return View(model); }
从上面代码的方法名可以看出,完成用户注册的主要实现在于UserManager.CreateAsync方法上,这个方法实现真是在Asp.net Identity帮我们实现,接下来到我们下载的源码来查看该方法的实现。具体的源码实现如下所示:
public virtual async Task<IdentityResult> CreateAsync(TUser user, string password) { ThrowIfDisposed(); var passwordStore = GetPasswordStore(); if (user == null) { throw new ArgumentNullException("user"); } if (password == null) { throw new ArgumentNullException("password"); } // UpdatePassword对密码进行Hash加密 var result = await UpdatePassword(passwordStore, user, password).WithCurrentCulture(); if (!result.Succeeded) { return result; } // 注册功能的实现 return await CreateAsync(user).WithCurrentCulture(); } public virtual async Task<IdentityResult> CreateAsync(TUser user) { ThrowIfDisposed(); await UpdateSecurityStampInternal(user).WithCurrentCulture(); var result = await UserValidator.ValidateAsync(user).WithCurrentCulture(); if (!result.Succeeded) { return result; } if (UserLockoutEnabledByDefault && SupportsUserLockout) { await GetUserLockoutStore().SetLockoutEnabledAsync(user, true).WithCurrentCulture(); } // 调用IUserStore的CreateAsync完成用户注册 await Store.CreateAsync(user).WithCurrentCulture(); return IdentityResult.Success; } // UserStore中CreateAsync的实现 public virtual async Task CreateAsync(TUser user) { ThrowIfDisposed(); if (user == null) { throw new ArgumentNullException("user"); } // 将实体添加进DbSet<User>集合中 _userStore.Create(user); // 调用SaveChanges将用户保存到数据库中 await SaveChanges().WithCurrentCulture(); }
看到这里是不是豁然开朗了很多的,其实Asp.net Identity内部注册功能的实现,我们完全可以自己来实现。其实现简单的说就是:
1. 对用户提交的数据进行验证
2. 对密码进行加密保存
3. 调用Microsoft.AspNet.Identity.EntityFramework命名空间下的UserStore类的CreateAsync方法将用户进行持久化。
4. UserStore类中的CreateAsync方法的实现也就是DbSet<User>.Add(entity)和SaveChanges()方法将对象持久化。
到这里还有一个问题,其实上面代码调用的是IUserStore接口中的CreateAsync方法,但具体的IUserStore对象是怎么注入进去的呢?
你带着这个疑惑去Asp.net MVC站点中去寻找其注入代码。此时,你可以发现在Startup.Auth.cs和Start.cs文件中有如下实现:
// Startup.cs 文件 public partial class Startup { public void Configuration(IAppBuilder app) { ConfigureAuth(app); } } // Start.Auth.cs文件 public void ConfigureAuth(IAppBuilder app) { // 配置数据库上下文、用户管理器和登录管理器,以便为每个请求使用单个实例 // ......... app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); // ........ } // IdentityConfig.cs文件 public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) { var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>())); // ........ }
看到上面标注红色的代码了吗,这里就是将UserStore注入的地方。看到这里,你是不是没有任何疑惑了。对于登录功能的实现大家同样可以按照这样的方法去探索。本来想一起分析下的,后面想想,还是留给大家去探索吧。
其实,在我们平时工作,只要学会如何使用Asp.net Identity机制来完成对应功能。那我们为什么还要研究其源码实现呢?我觉得有两点:
上面介绍了研究源码的两大作用,那我们从Asp.net Identity内部实现中又学到了什么呢?
通过第四部分的代码分析,Asp.net Identity中注册功能的实现主要分为的4点中,我们可以学到如下几点:
所以,如果你觉得你现在的工作得到提高的话,完全不需要去什么群里咨询其他的推荐什么书籍什么,从现在开始就开始研究源码吧。如果不知道研究什么源码的话,完全可以从微软的一些开源代码开始,例如就从Asp.net Identity源码开始,不要担心研究完之后,还是怕不能提高,只要你理解和领悟了,你不想提高都难。另外再推荐大家研究下ABP的实现,我最近就在研究它,希望理解透彻之后,再写一个小的Web框架来巩固自己的研究。到时候也会把自己的一些研究心得分享到这里。
到这里,本篇文章的介绍就结束了,希望这篇文章可以帮助朋友对微软的用户权限管理框架有进一步的了解,以及希望哪些想提高的朋友,从现在开始就来和我一起来研究微软的开源框架和ABP框架吧。记得研究之后,分享到这里与大家共享哦。