天天看點

ASP.NET 5 Identity

ASP.NET 5 Identity

<a href="http://www.cnblogs.com/jesse2013/p/membership.html">Membership三步曲之入門篇 - Membership 基礎示例</a>

<a href="http://www.cnblogs.com/jesse2013/p/membership-part2.html">Membership三步曲之進階篇 - 深入剖析Provider Model</a>

<a href="http://www.cnblogs.com/jesse2013/p/membership-part3.html">Membership三步曲之進階篇 - 從Membership到 ASP.NET Identity</a>

其實說來慚愧,我自己對 ASP.NET Identity 的了解及運用,僅限在使用 AuthorizeAttribute、FormsAuthentication.SetAuthCookie 等一些操作,背後的原理及其發展曆程并不是很了解,是以我當時在 ASP.NET 5 中進行身份驗證操作,才會讓自己有種“無助”的感覺,周末的時候,閱讀了 Jesse Liu 的這幾篇博文,然後又找了一些相關資料,自己似乎懂得了一些,但好像又沒有完全了解,既然說不出來,那就用“筆”記下來。

ASP.NET 5 中,關于身份驗證的變化其實不大,還是 MVC5 的那一套,隻不過配置有的變化罷了,使用 VS2015 建立 MVC 項目的時候,點選“Change Authentication”會出現下面四個選項:

ASP.NET 5 Identity

如果建立的是 ASP.NET 5 項目,Authentication 預設是不可更改:

ASP.NET 5 Identity

使用 VS2015 分别建立 MVC5 及 ASP.NET 5 的示例項目,你會發現 MVC5 中關于身份驗證的代碼及配置非常複雜,而在 ASP.NET 5 中則相對來說簡化下,首先,在 Startup.cs 檔案中的 ConfigureServices 方法中,有如下配置:

上面代碼中,AddDefaultIdentity 和 AddIdentityEntityFramework 其實是一個意思(“捆綁銷售”),所在程式集:Microsoft.AspNet.Identity.EntityFramework,AddEntityFramework 和 AddIdentityEntityFramework 使用的是同一個 DbContext,當然也可以進行對身份驗證上下文進行分開管理,比如我們有可能多個應用程式共享一個身份驗證的上下文。ConfigureServices 方法的解釋為:This method gets called by the runtime,表示這個方法在應用程式運作的時候注冊使用的服務,有點類似于元件化的應用,比如 ASP.NET 5 隻是一個基礎 Web 站點,你可以在這個應用中添加你想要的元件或子產品,比如你想使用 WebAPI,你隻需要在 project.json 中添加 Microsoft.AspNet.Mvc.WebApiCompatShim 程式包,然後在 ConfigureServices 方法中進行服務注冊就行了:services.AddWebApiConventions();。

AddDefaultIdentity 注冊的三個基礎類型:

IdentityDbContext&lt; IdentityUser &gt;:ApplicationDbContext 繼承實作。

IdentityUser:ApplicationUser 繼承實作。

IdentityRole

注冊完成之後,就是配置使用了,在 Startup.cs 的 Configure 方法中進行配置使用:app.UseIdentity();,表示應用程式啟用身份驗證,如果把這段代碼注釋掉的話,你會發現整個應用程式的身份驗證就失效了,Configure 方法解釋是:Configure is called after ConfigureServices is called,在上面 AddDefaultIdentity 注冊中,其實包含了很多内容,關于身份驗證基本上就這三個類型,ASP.NET Identity 直接的操作通過注冊的這三個類型進行以來注入,比如後面會遇到的 UserManager 和 SignInManager,但檢視這部分的源代碼,在 Microsoft.AspNet.Identity.EntityFramework 中并沒有加入進來。

我們也可以在 Configure 中進行自定義配置,配置方法:app.UseCookieAuthentication。當通路 Action 的身份驗證失效後,跳轉到“/Account/Login”進行登入,檢視 AccountController 中的示例代碼,你會發現有下面的東西:

檢視整個的應用程式的代碼,發現我們并沒有注冊 UserManager、SignInManager 類型的依賴注入,那是怎麼注入的呢?其實注入的類型不是 UserManager 和 SignInManager,而是 IdentityUser,在 ConfigureServices 中我們添加過這樣的代碼:<code>services.AddDefaultIdentity&lt;ApplicationDbContext, ApplicationUser, IdentityRole&gt;(Configuration);</code>,這是最重要的,之後所有身份驗證操作所用到的基類型都是從這裡來的,在 IdentityServiceCollectionExtensions 中的 AddIdentity 操作中,我們發現了下面這樣的代碼:

最主要的操作是,通過 ASP.NET Identity 的 SignInManager.PasswordSignInAsync 操作,進行驗證身份密碼,傳回 SignInStatus 類型的驗證結果:

我們來看一下 SignInManager.PasswordSignInAsync 中究竟幹了什麼事:

PasswordSignInAsync 還有一個重寫方法,是擷取使用者資訊的:<code>UserManager.FindByNameAsync(userName, cancellationToken);</code>,接着檢視 FindByNameAsync 的定義,會找到這段代碼:<code>Store.FindByNameAsync(userName, cancellationToken)</code>,Store 是什麼?類型定義為:<code>IUserStore&lt;TUser&gt; Store</code>,它就像一個倉庫,為使用者驗證提供查詢及存儲服務,除了 IUserStore,在 UserManager 中,你還會發現有很多的“Store”,比如 IUserLoginStore、IUserRoleStore、IUserClaimStore 等等,但都是繼承于 IUserStore,在 ConfigureServices 進行配置服務的時候,services.AddIdentity 還有一個 AddEntityFrameworkStores 方法,範型類型為 TContext,上面所有的 Store 上下文都是從它繼承來的,再檢視 AddEntityFrameworkStores 的實作:

SignInManager 的具體實作代碼,你會發現,關于使用者的擷取及存儲,都是通過 UserManager 進行操作的,而 UserManager 又是通過 IUserStore 的具體實作類進行操作的,SignInManager 隻不過是一個使用者驗證的操作類,比如我們一開始說到的 SignInManager.PasswordSignInAsync,上面已經貼出代碼了,你會看到基本上都是 UserManager.什麼,比如 UserManager.CheckPasswordAsync、UserManager.SupportsUserLockout、UserManager.AccessFailedAsync 等等,在 PasswordSignInAsync 代碼實作中,不關于使用者操作的,最核心的就是這段代碼:<code>SignInOrTwoFactorAsync(user, isPersistent, cancellationToken);</code>,檢視其具體實作:

再次抛開一大堆的 UserManager 操作,找到最核心的:<code>Context.Response.SignIn(StoreTwoFactorInfo(userId, loginProvider))</code>,StoreTwoFactorInfo 方法傳回類型為 ClaimsIdentity,在傳回之前,根據 userId 建立 Claim 對象,并添加到 ClaimsIdentity 集合中,接下來的操作就是:<code>Context.Response.SignIn</code>,将使用者身份資訊輸入到目前上下文,接着檢視 HttpResponse 抽象類關于 SignIn 的定義:

在以前如果使用 SignIn,其調用方式是 <code>System.Web.Security.FormsAuthentication.SetAuthCookie("userName", false);</code>,采用的是 Forms 認證,但是在 ASP.NET 5 中,已經通路不到 SetAuthCookie 了,原來的 SetAuthCookie 實作方式不知道是怎樣的,如果在 ASP.NET 5 中實作 SetAuthCookie 類似的效果,我們該怎麼做呢?隻需要在 Startup.cs 的 Configure 方法中進行下面配置:

上面的操作其實就是之前的 <code>SignInManager.PasswordSignInAsync</code> 一樣,隻不過是一個簡化版本,另外,IdentityOptions.ApplicationCookieAuthenticationType 也沒什麼神奇的地方,就是一個類型字元串:

Login 登入驗證效果:

ASP.NET 5 Identity

總結:上面也說了不少内容,說真的,其實我也不知道自己說了什麼,有幾點感觸需要總結下,在多個應用程式共享身份驗證的時候(CookieDomain),不管是使用 FormsAuthentication,還是使用 SignInManager.SignInAsync,又或者使用 UserStore 進行使用者管理,但使用者進行驗證的程式隻有一個,這個按照自己的想法,想怎麼實作就怎麼實作,其他的應用程式都隻不過是判斷使用者是否通過驗證請求、及擷取使用者辨別的,就這兩個操作,使用者的驗證不管上面的何種實作,我們都可以通過 User.Identity 擷取使用者驗證的資訊,類型為 IIdentity。

本文轉自田園裡的蟋蟀部落格園部落格,原文連結:http://www.cnblogs.com/xishuai/p/asp-net-5-identity.html,如需轉載請自行聯系原作者

繼續閱讀