[ASP.NET MVC] ASP.NET Identity登入技术应用
2016-02-17 16:09
686 查看
[ASP.NET MVC] ASP.NET Identity登入技术应用
情景
ASP.NET Identity是微软所贡献的开源项目,用来提供ASP.NET的验证、授权等等机制。在ASP.NET Identity里除了提供最基础的:用户注册、密码重设、密码验证等等基础功能之外,也提供了进阶的:Cookie登入、Facebook登入、Google登入等等进阶功能。套用这些功能模块,让开发人员可以快速的在ASP.NET站台上,提供验证、授权等等机制。![](https://oscdn.geek-share.com/Uploads/Images/Content/202002/02/a5c9936f4d35d01d7cb32ab330675563.png)
但是在企业中,开发人员常常会遇到一种开发情景就是:企业里已经有一套既有身分系统,这个系统提供了:用户注册、密码重设、密码验证等等功能,新开发的ASP.NET站台,必须要串接既有身分系统来提供验证、授权等等机制。这个既有身分系统,可能是大卖场会员管理系统、也可能是银行帐户管理系统,它们的注册审核机制有一套严谨并且固定的流程。
在这样的开发情景中,开发人员可能会选择透过程序接口、OAuth机制等等方式,将既有身分系统整合成为ASP.NET Identity的验证提供者。这样两个系统之间的整合,除了有一定的高技术门坎之外。在整合之后,两个系统之间互相重迭的功能模块,操作流程的冲突该如何处理,也是一个需要额外考虑的复杂问题。
![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E6%83%85%E6%99%AF02.png)
一个好消息是,ASP.NET Identity拥有高度模块化的软件架构。在ASP.NET Identity中,将Cookie登入、Facebook登入、Google登入等等功能模块,切割为独立的ASP.NET Security套件。开发人员完全可以直接套用ASP.NET Security套件,快速整合既有的身分系统,就可以提供ASP.NET站台所需的验证、授权等等机制。本篇文章介绍如何套用ASP.NET Security来整合既有身分系统,用以提供ASP.NET站台所需的验证、授权等等机制。主要为自己留个纪录,也希望能帮助到有需要的开发人员。
ASP.NET Security - GitHub
![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E6%83%85%E6%99%AF03.png)
范例
范例程序代码:下载地址开发
开始套用ASP.NET Security之前,先建立一个空白的MVC项目,来提供一个新的ASP.NET站台。并且变更预设的Web服务器URL为:「http://localhost:41532/」,方便完成后续的开发步骤。![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E9%96%8B%E7%99%BC01.png)
![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E9%96%8B%E7%99%BC02.png)
再来在MVC项目里加入三个ASP.NET Security的NuGet套件参考:Microsoft.AspNet.Authentication、Microsoft.AspNet.Authentication.Cookies、Microsoft.AspNet.Authentication.Facebook。
![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E9%96%8B%E7%99%BC03.png)
接着建立AccountController以及相关的View,用以提供登入页面,让使用者可以选择使用哪种模式登入系统。
public class AccountController : Controller { // Methods public IActionResult Login(string returnUrl = null) { // ViewData this.ViewData["ReturnUrl"] = returnUrl; // Return return View(); } }
再来在MVC项目内加入下列程序代码,用以挂载与设定后续要使用的两个CookieAuthenticationMiddleware。(关于程序代码的相关背景知识,请参阅技术剖析说明:ASP.NET Identity登入技术剖析)
public class Startup { public void ConfigureServices(IServiceCollection services) { // Authentication services.AddAuthentication(options => { options.SignInScheme = IdentityOptions.Current.ExternalCookieAuthenticationScheme; }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { // Authentication app.UseCookieAuthentication(options => { options.AuthenticationScheme = IdentityOptions.Current.ApplicationCookieAuthenticationScheme; options.AutomaticAuthenticate = true; options.AutomaticChallenge = true; options.LoginPath = new PathString("/Account/login"); }); app.UseCookieAuthentication(options => { options.AuthenticationScheme = IdentityOptions.Current.ExternalCookieAuthenticationScheme; options.AutomaticAuthenticate = false; options.AutomaticChallenge = false; options.LoginPath = null; }); } }
最后在MVC项目内,建立ExistingIdentitySystem这个类别用来仿真既有身分系统。为了方便理解系统,ExistingIdentitySystem里的PasswordSignIn(密码登入)、ExternalSignIn(第三方登入ex:FB登入)等方法都直接回传成功讯息,而GetUserById(取得使用者)这个方法则是直接回传固定的用户信息。(在正式环境开发时,上述方法可以实作为透过WebAPI、或是直接连通数据库等等方式,与既有身分系统取得相关信息。)
public class ExistingIdentitySystem { // Methods public ExistingUser GetUserById(string userId) { // Result var user = new ExistingUser(); user.Id = "Clark.Lab@hotmail.com"; user.Name = "Clark"; user.Birthday = DateTime.Now; // Return return user; } public bool PasswordSignIn(string userId, string password) { // Return return true; } public bool ExternalSignIn(string userId, string externalProvider) { switch (externalProvider) { case "Facebook": return true; default: return true; } } } public class ExistingUser { // Properties public string Id { get; set; } public string Name { get; set; } public DateTime Birthday { get; set; } }
开发 - Facebook Authentication
完成上述步骤后,接着着手开发Facebook验证。首先开发人员可以到Facebook开发者中心(https://developers.facebook.com/),注册一个新的APP账号。(测试用的Site URL为先前步骤定义的:「http://localhost:41532/」)![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E9%96%8B%E7%99%BCFacebook01.png)
接着在MVC项目内加入下列程序代码,用以挂载与设定FacebookAuthenticationMiddleware。在这其中AppId、AppSecret是Facebook开发者中心提供的APP账号数据,而Scope、UserInformationEndpoint两个参数则是定义要额外取得用户的E-Mail信息。
public class Startup { public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { // Authentication app.UseFacebookAuthentication(options => { options.AppId = "770764239696406"; options.AppSecret = "2eecc0b9ef785e43bcd4779e2803ba0f"; options.Scope.Add("email"); options.UserInformationEndpoint = "https://graph.facebook.com/v2.5/me?fields=id,name,email"; }); } }
再来打开AccountController加入下列程序代码以及对应的View,用以提供ASP.NET站台处理Facebook这类的第三方登入(ExternalLogin)。在这其中,ExternalLogin用来发起一个验证挑战(Challenge),系统会依照externalProvider参数,来决定是要向Facebook或是其他第三方系统做验证。
当用户通过验证后,系统会调用ExternalLoginCallback来处理验证结果。在ExternalLoginCallback里会取得验证结果中FBUser的UserId,用来与ExistingIdentitySystem做验证。如果验证通过,会接着从ExistingIdentitySystem取得对应的ExistingUser、再转换为APPUser来真正登入系统。(关于程序代码的相关背景知识,请参阅技术剖析说明:ASP.NET Identity登入技术剖析)
public class AccountController : Controller { public IActionResult ExternalLogin(string externalProvider, string returnUrl = null) { // AuthenticationProperties var authenticationProperties = new AuthenticationProperties(); authenticationProperties.Items.Add("ExternalProvider", externalProvider); authenticationProperties.RedirectUri = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }); // Return return new ChallengeResult(externalProvider, authenticationProperties); } public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null) { // AuthenticateContext var authenticateContext = new AuthenticateContext(IdentityOptions.Current.ExternalCookieAuthenticationScheme); await this.HttpContext.Authentication.AuthenticateAsync(authenticateContext); // AuthenticateInfo string userId = authenticateContext.Principal.FindFirst(ClaimTypes.Email).Value; string externalProvider = authenticateContext.Properties["ExternalProvider"] as string; // Login var existingIdentitySystem = new ExistingIdentitySystem(); if (existingIdentitySystem.ExternalSignIn(userId, externalProvider) == false) { throw new InvalidOperationException(); } // ExistingUser var existingUser = existingIdentitySystem.GetUserById(userId); if (existingUser == null) throw new InvalidOperationException(); // ApplicationUser var applicationIdentity = new ClaimsIdentity(IdentityOptions.Current.ApplicationCookieAuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role); applicationIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, existingUser.Id)); applicationIdentity.AddClaim(new Claim(ClaimTypes.Name, existingUser.Name)); var applicationUser = new ClaimsPrincipal(applicationIdentity); // Cookie await this.HttpContext.Authentication.SignInAsync(IdentityOptions.Current.ApplicationCookieAuthenticationScheme, applicationUser); await this.HttpContext.Authentication.SignOutAsync(IdentityOptions.Current.ExternalCookieAuthenticationScheme); // Return return Redirect(returnUrl); } }
开发 - Password Authentication
完成上述步骤后,接着着手开发Password验证。打开AccountController加入下列程序代码以及对应的View,用以提供ASP.NET站台处理Password验证。在这其中,PasswordLogin会接收用户输入的账号密码,用来与ExistingIdentitySystem做验证。如果验证通过,会接着从ExistingIdentitySystem取得ExistingUser、再转换为APPUser来真正登入系统。(关于程序代码的相关背景知识,请参阅技术剖析说明:ASP.NET Identity登入技术剖析)public class AccountController : Controller { public async Task<IActionResult> PasswordLogin(string userId, string password, string returnUrl = null) { // Login var existingIdentitySystem = new ExistingIdentitySystem(); if (existingIdentitySystem.PasswordSignIn(userId, password) == false) { throw new InvalidOperationException(); } // ExistingUser var existingUser = existingIdentitySystem.GetUserById(userId); if (existingUser == null) throw new InvalidOperationException(); // ApplicationUser var applicationIdentity = new ClaimsIdentity(IdentityOptions.Current.ApplicationCookieAuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role); applicationIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, existingUser.Id)); applicationIdentity.AddClaim(new Claim(ClaimTypes.Name, existingUser.Name)); var applicationUser = new ClaimsPrincipal(applicationIdentity); // Cookie await this.HttpContext.Authentication.SignInAsync(IdentityOptions.Current.ApplicationCookieAuthenticationScheme, applicationUser); await this.HttpContext.Authentication.SignOutAsync(IdentityOptions.Current.ExternalCookieAuthenticationScheme); // Return return Redirect(returnUrl); } }
使用
完成开发步骤后,当系统执行到打上[Authorize]标签的Controller或是Action时,就会跳转到Login页面。public class HomeController : Controller { [Authorize] public IActionResult Contact() { ViewData["Message"] = "Hello " + User.Identity.Name + "!"; return View(); } }
![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E4%BD%BF%E7%94%A801.png)
![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E4%BD%BF%E7%94%A802.png)
使用 - Facebook Authentication
在Login页面,当使用者选择使用Facebook验证,系统会跳转到Facebook页面进行验证与授权。完成验证授权的相关步骤后,使用者就可以进入被打上[Authorize]标签的Controller或是Action。![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E4%BD%BF%E7%94%A8Facebook01.png)
![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E4%BD%BF%E7%94%A8Facebook02.png)
![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E4%BD%BF%E7%94%A8Facebook03.png)
使用 - Password Authentication
在Login页面,当使用者选择使用Password验证,系统会使用Login页面上输入的账号密码来进行验证与授权。完成验证授权的相关步骤后,使用者就可以进入被打上[Authorize]标签的Controller或是Action。![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E4%BD%BF%E7%94%A8Password01.png)
![](https://raw.githubusercontent.com/Clark159/clark159.github.io/master/_posts/%5BASP.NET%20MVC%5D/%5BASP.NET%20MVC%5D%20ASP.NET%20Identity%E7%99%BB%E5%85%A5%E6%8A%80%E8%A1%93%E6%87%89%E7%94%A8/%E4%BD%BF%E7%94%A8Password02.png)
范例
范例程序代码:下载地址相关文章推荐
- ASP.NET 免费开源控件
- Asp.Net MVC3 简单入门详解过滤器Filter
- <转载>提高 ASP.NET Web 应用性能的 24 种方法和技巧
- Asp.net中GridView使用详解
- ASP.NET MVC 网站开发流程
- asp.net时间显示
- 【Asphyre引擎】发布了新版本V101
- ModifyInfo.aspx.cs代码
- 【视频】 ASP.NET MVC5&微信公众平台整合开发实战
- asp.net WebForm 事件响应模型
- asp.net 的onclick=""事件
- asp.net 中 AutoPostBack 和IsPostBack浅析
- 基于@Aspect的AOP注解配置
- 【ASP.NET Identity系列教程(三)】Identity高级技术
- ASPCMS安全相关
- ASP.NET 身份验证机制
- asp.net mvc 如何调用微信jssdk接口:分享到微信朋友(圈)| 分享到qq空间
- ASP.NET页面之间传递值的几种方式
- asp.net页面的AutoEventWireup="true"属性设置
- ASP.NET基础面试题