翻译自:http://www.asp.net/identity/overview/getting-started/introduction-to-aspnet-identity ,略有改动。
在 2005 年,ASP.NET 成员资格用于解决站点在成员资格方面的常见需求。这些需求包括表单身份验证,一个用于存储用户名、密码和用户资料信息 (profile) 的 SQL Server 数据库。而在现如今,对于 Web 应用程序的数据存储,我们拥有了更多的选项。与此同时,大多数程序员希望自己的站点能够使用第三方用户标识提供商提供的身份验证和授权功能。但是,由于 ASP.NET 成员资格自身设计的限制,其已经难以适应这种变化:
数据库架构为 SQL Server 而设计,且无法修改。虽然你可以添加额外的用户资料信息,但这些信息被存入了一张不同的数据表。这使得这些信息难以访问(除了通过 Profile Provider API)。
虽然提供程序系统允许你对后台数据存储结构的修改,但是该系统的设计基于一个假设,即对关系型数据库的使用。虽然你也可以写一个面向非关系型存储机制的提供程序(例如 Windows Azure 存储表),但在那之后,围绕着相关的设计,你还需要大量的工作。这包括编写大量的代码,以及为那些 NoSQL 数据库不支持的方法抛出一大堆的 System.NotImplementedException 异常。
由于“登录/登出”功能基于表单身份验证,因此该成员资格系统无法用于 OWIN。OWIN 包括了一些用于身份验证的中间件。其中有对使用外部身份标识提供商(例如 Microsoft 账户, Facebook, Google, Twitter 等)进行登录的支持;对使用组织账号(来自于组织内部的 Active Directory 或者 Windows Azure Active Directory 等)进行登录的支持。OWIN 同时提供了对 OAuth 2.0, JWT and CORS (Cross-Origin Resource Sharing,跨域资源共享) 的支持。
ASP.NET 简单成员资格是为 ASP.NET Web Pages 开发的一套成员资格系统。它与 WebMatrix 和 Visual Studio 2010 SP1 一同发布。其目的是简化为 Web Pages 应用程序添加成员资格功能的过程。
虽然,简单成员资格的确简化了添加用户资料信息的过程,但它依旧存在 ASP.NET 成员资格的其他问题。它也有自身的一些限制:
难于将成员资格系统的数据存储在非关系型存储结构中。
无法将其和 OWIN 一起使用。
它不能很好的和已有的 ASP.NET 成员资格提供程序一起工作,它还是不可扩展的。
ASP.NET Universal Providers 能够将成员资格信息存储在 Windows Azure SQL 数据库中,它同时能够和 SQL Server Compact 一起工作。Universal Providers 构建于 Entity Framework Code First 之上,这意味着 Universal Providers 可以将数据存入任何支持实体框架的存储系统。Universal Providers 所使用的数据库架构也得到了极大地简化。
由于 Universal Providers 构建于 ASP.NET 成员资格基础架构之上,因此它也同样具有 SqlMembership 提供程序相同的限制。它们为关系型数据库而设计,难于自定义用户资料和其他用户信息。这些提供程序也依然使用表单身份验证完成“登录/登出”操作。
在 ASP.NET 成员资格系统不断演化的这些年里,ASP.NET 团队也不断地得到来自用户的大量反馈。
“用户需要在应用程序中注册,之后将会通过使用注册时的用户名和密码进行登录。”这一假设现在已经不在成立。Web 网络已经更加社交化,使得用户可以与其他人通过诸如 Facebook, Twitter 之类的社交渠道实时的交互。开发人员希望用户能够使用它们的社交网络身份标识进行登录,以便在网站上提供更好的用户体验。一个现代的成员资格系统必须能够支持基于跳转的登录操作,用以支持 Facebook, Twitter 等身份验证提供商。
伴随着 Web 开发的不断演化,Web 开发的模式也在不断变化。对应用程序代码的单元测试已经变成应用程序开发人员的主要关注点。在 2008 年,ASP.NET 添加了一个基于“模型-视图-控制器 (MVC)”模式的新框架。该框架的目的之一既是帮助开发人员构建“可单元测试 (unit testable)”的 ASP.NET 应用程序。希望对其应用程序逻辑进行单元测试的开发人员同样希望能够对成员资格系统进行单元测试。
考虑 Web 应用程序开发中的这些变化,ASP.NET 带来了下列特性:
One ASP.NET Identity 系统
更容易加入用户的个人资料信息
持久化控制
单元测试能力
角色提供程序
基于声明的 (Claims Based)
社交账号登录提供程序 (Social Login Providers)
Windows Azure Active Directory
OWIN 集成
NuGet 包
在 Visual Studio 2013 的若干个项目模板中都内置了 ASP.NET Identity,包括 ASP.NET MVC, Web Forms, Web API 和 SPA。在这个演练中,我们将阐述,这些项目是如何使用 ASP.NET Identity 来添加对用户的“注册”/“登录”/“登出”等功能的。
ASP.NET Identity 按照下列流程实现。这篇文章的目的在于为你提供一个对 ASP.NET Identity 的简单介绍。你可以依照顺序一步步地阅读,也可以只阅读特定的细节部分。对于使用 ASP.NET Identity 创建应用程序更详细的说明,包括使用新的 API 来添加用户、角色和用户资料信息,参见文章结尾的 “后续步骤” 一节。
使用 “个人用户账户” (Individual Accounts) 创建一个 ASP.NET MVC 应用程序。你可以将 ASP.NET Identity 使用在 ASP.NET MVC, Web Forms, Web API, SignalR 等框架中,在本文章里,我们从一个 ASP.NET MVC 应用程序开始。
新建的项目包含了下列三个 ASP.NET Identity 包:
Microsoft.AspNet.Identity.EntityFramework
这个包容纳了 ASP.NET Identity 基于 Entity Framework 的实现。它将 ASP.NET Identity 的数据和架构存入 SQL Server。
Microsoft.AspNet.Identity.Core
这个包容纳了 ASP.NET Identity 的核心接口。它可以用来编写 ASP.NET Identity 的其他实现,用以支持其他持久化存储系统,如 Windows Azure 表存储, NoSQL 数据库等等。
Microsoft.AspNet.Identity.OWIN
这个包为 ASP.NET 应用程序提供了将 ASP.NET Identity 引入到 OWIN 身份验证的功能。当你在为应用程序加入登录功能,调用 OWIN Cookie 身份验证中间件来生成 cookie 时,会用到这个包。
创建一个用户。
运行应用程序,然后点击 注册 (Register) 链接创建一个用户。以下图片展示了收集用户名和密码的注册页面。
下列代码的第 8 到第 9 行展示了当用户点击 注册 (Register) 按钮时,Account 控制器的 Register 动作将通过调用 ASP.NET Identity API 创建一个新的用户:
1 [HttpPost] 2 [AllowAnonymous] 3 [ValidateAntiForgeryToken] 4 public async Task<ActionResult> Register(RegisterViewModel model) 5 { 6 if (ModelState.IsValid) 7 { 8 var user = new ApplicationUser() { UserName = model.UserName }; 9 var result = await UserManager.CreateAsync(user, model.Password); 10 if (result.Succeeded) 11 { 12 await SignInAsync(user, isPersistent: false); 13 return RedirectToAction("Index", "Home"); 14 } 15 else 16 { 17 AddErrors(result); 18 } 19 } 20 21 // If we got this far, something failed, redisplay form 22 return View(model); 23 }
登录
如果用户创建成功,那么它将通过对 SignInAsync 方法的调用完成登录操作。
1 [HttpPost] 2 [AllowAnonymous] 3 [ValidateAntiForgeryToken] 4 public async Task<ActionResult> Register(RegisterViewModel model) 5 { 6 if (ModelState.IsValid) 7 { 8 var user = new ApplicationUser() { UserName = model.UserName }; 9 var result = await UserManager.CreateAsync(user, model.Password); 10 if (result.Succeeded) 11 { 12 await SignInAsync(user, isPersistent: false); 13 return RedirectToAction("Index", "Home"); 14 } 15 else 16 { 17 AddErrors(result); 18 } 19 } 20 21 // If we got this far, something failed, redisplay form 22 return View(model); 23 }
1 private async Task SignInAsync(ApplicationUser user, bool isPersistent) 2 { 3 AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); 4 5 var identity = await UserManager.CreateIdentityAsync( 6 user, DefaultAuthenticationTypes.ApplicationCookie); 7 8 AuthenticationManager.SignIn( 9 new AuthenticationProperties() { 10 IsPersistent = isPersistent 11 }, identity); 12 }
上述代码 SingInAsync 方法中的第 5 到第 6 行生成了一个 ClaimsIdentity。由于 ASP.NET Identity 和 OWIN Cookie 身份验证是基于“声明” (claims) 的系统,所以框架要求应用程序为用户生成一个 ClaimsIdentity。ClaimsIdentity 包含有关于用户的所有声明信息,例如用户所属的角色。你也可以在这个阶段为用户添加更多的声明。
上述代码 SingInAsync 方法中的第 8 到第 11 行完成了用户的登录操作。它使用来自 OWIN 的 AuthenticationManager,调用它的 SignIn 方法,并传入生成的 ClaimsIdentity。
1 // POST: /Account/LogOff 2 [HttpPost] 3 [ValidateAntiForgeryToken] 4 public ActionResult LogOff() 5 { 6 AuthenticationManager.SignOut(); 7 return RedirectToAction("Index", "Home"); 8 }上述代码中的第 6 行展示了 OWIN 的 AuthenticationManager.SignOut 方法。该方法类似于在 Web Forms 中, FormsAuthentication 使用的 FormsAuthentication.SignOut 方法。
以下图表展示了 ASP.NET Identity 系统的组成部分(点击这里或者图表显示大图)。绿色的包构成了 ASP.NET Identity 系统,其他的所有包都是使用了 ASP.NET Identity 的 ASP.NET 应用程序所需要引入的依赖项。
以下是对之前没有提到的几个 NuGet 包的简单说明:
对于将已经在使用 ASP.NET 成员资格或者简单成员资格的 Web 应用程序,可以参考这篇文章,将应用程序的身份验证系统迁移至 ASP.NET Identity。