1. 程式人生 > >ASP.NET沒有魔法——Identity與Owin

ASP.NET沒有魔法——Identity與Owin

註冊方法 委托 地址 結構 錯誤提示 請求 ger 特殊 設計

  上篇文章介紹了如何在ASP.NET MVC項目中引入Identity組件來實現用戶註冊、登錄及身份驗證功能,並且也提到了Identity是集成到Owin中的,本章就來介紹一下什麽是Owin以及如何使用Owin來增強Identity的功能。

  本章的主要內容有:

  ● 什麽是Owin
  ● 關於Katana
  ● Owin與宿主IIS
  ● Owin與Identity的集成
  ● Identity在Owin中的特殊用法

什麽是Owin

  Owin(Open Web Server Interface)它是一個.NET Web服務器和Web程序之間的接口標準,其目的是為了應用程序與服務器解耦。為什麽需要解耦?因為ASP.NET應用(不包含ASP.NET Core和mono)都需要部署在IIS服務器上,而通過實現Owin的接口,可以將一個控制臺程序作為Web應用程序的宿主。

  Owin實質上是提供了一個名稱為環境字典的IDictionary<string, object>類型來存儲所有數據,包括請求和響應數據。在這個字典中Owin定義了一系列的核心鍵值對:

  技術分享

  另外還有一個重要的核心類型是一個參數為IDictionary<string, object>(即上面分析用於存儲數據的類型)的代理:Func<IDictionary<string, object>, Task>,每一個委托都是用於處理請求的一個獨立單元,將多個獨立單元集合到一起就形成Owin的處理管道,另外返回值是一個Task,換句話說所有的處理單元或者說中間件都需要設計成異步的,可以提高系統的吞吐量。

  更多信息可參考文檔:http://owin.org/html/owin.html

關於Katana

  Owin既然是一個接口標準,那麽就一定有實現,微軟對Owin的實現是一個名為Katana的項目(https://github.com/aspnet/AspNetKatana),該項目中的組件大部分以Microsoft.Owin作為前綴,一下是github上部分組件目錄:

  技術分享

  Katana主要有4個部分組成,分別是宿主、服務器、中間件和應用,如下圖整個結構是分層次的,由下到上:

  技術分享

  ● Host:也就是宿主,使用Katana可選Owin的宿主有IIS自定義宿主(如console程序)

以及OwinHost.exe。前面兩個比較好理解,對於OwinHost.exe其實是Katana項目的一個用於啟動Owin應用的程序,通過命令行的方式就可以運行指定的Owin應用(註:所有的宿主都可以通過Nuget管理器安裝)。

  技術分享


  ● Server:服務器,就是用來接收、響應請求的組件。
    ○ 在IIS下,通過安裝Microsoft.Owin.Host.SystemWeb,將Owin的HttpModule“動態”註冊到IIS處理管道中接收處理HTTP請求
    ○ 在自定義的宿主中,通過安裝Microsoft.Owin.Host.HttpListener,以代碼的形式顯式的根據地址和端口打開一個Soket來監聽請求。OwinHost.exe也是使用該組件來監聽請求。
  ● Middleware:中間件,實質上就是一個實現了Func<IDictionary<string, object>, Task>的委托,也可以簡單通過繼承OwinMiddleware類型來創建。創建完成後在Owin的Startup類型中通過IAppBuilder類型Use方法將其添加到管道中。
  ● Application:應用層,Owin以及Katana都沒有考慮一種新的開發應用的方式,換句話說可以沿用之前的mvc、webapi、Signalr或者是靜態頁面等方式來開發應用。

Owin與宿主IIS

  Owin在IIS的宿主(Microsoft.Owin.Host.SystemWeb)其實是一個IHttpModule的實現:

  技術分享

  而使用HttpModule對IIS的請求處理管理進行拓展的一般方法都是使用配置的方式在Web.config文件中添加。但是引入Owin後其實沒有在配置文件裏面加入任何配置,而是通過以下代碼在程序運行時註冊的:

  技術分享

  Owin在使用IIS作為宿主時就是通過HttpModule的形式對原有的ASP.NET HTTP請求通道進行了拓展,請求在ASP.NET的管道處理過程中通過HttpModule拓展的形式將整個請求轉移到Owin管道處理。

Owin與Identity的集成

  Identity就是通過Owin中間件的方式集成到處理管道中的,如下圖代碼:

  技術分享

  另外在安裝Identity的同時還在Web.config文件中加入了以下配置:

  技術分享

  刪除了Form驗證的HttpModule,這裏的原因也是identity的驗證可以代替Form驗證,所以對這個功能進行了刪除。

  運行時的HttpModule列表:

  技術分享

Identity在Owin中的特殊用法

  (註:以下代碼可以參考ASP.NET MVC默認帶有身份驗證的項目模板,部分代碼有改動DbContext名稱、命名空間以及省略了部分配置,如雙因子驗證等)

  說是特殊用法,實際上是在每一次請求時都會創建一個DbContext、UserManager以及SignInManager放在Owin的環境字典中,那麽意味著整個請求過程中都可以通過Owin獲取這些實例對用戶進行操作。

  1. 使用前準備,封裝DbContext的創建過程:

  技術分享

  2. 封裝UserManager創建過程(註:UserManager的創建中還包含了對用戶名、密碼的驗證配置以及一些驗證配置信息):

  技術分享

  3. 封裝SignInManager:

  技術分享

  SignInManager中依賴的UserManager來自Owin的上下文對象。

  另外這裏還對通過用戶信息生成身份信息做了封裝:

  技術分享

  4. 在Owin的Startup文件中加入以下代碼,確保在請求時創建這些對象:

  技術分享

  需要註意的是CreatePerOwinContext來自Identity的Owin拓展:

  技術分享

  而CreatePerOwinContext方法實際上是為Owin管道添加了一個名稱為IdentityFactoryMiddleware的Owin中間件,意思就是上面的三個方法就在Owin管道中插入了三個相同的中間件(但參數不同),以下是IdentityFactoryMiddleware調用的代碼:

  技術分享

  5. 修改Controller代碼,在實現用戶註冊、登錄功能時,從Owin的Context中獲取UserManager及SignInManager來實現:

  技術分享

  註冊方法,代碼來自默認模板(相比之前的代碼加入了對創建結果的判斷):

  技術分享

  登錄方法,代碼來自默認模板(相比之前的代碼加入了對創建結果的判斷):

  技術分享

  6. 運行效果:

  技術分享

  技術分享

  7. 安裝Identity的漢化包:

  從上面的錯誤提示中可以看到英文的提示,它們是通過在Controller中對ModelState信息添加錯誤信息,然後在View中通過Html.ValidationSummary方法顯示出來的(更多與Model相關的內容後續介紹)。

  但是由於創建用戶返回的結果信息是英文的,所以顯示也是英文,如果要把它替換成中文,那麽需要安裝漢化包:Microsoft.AspNet.Identity.Core.zh-Hans:

  技術分享

  安裝完成運行效果:

  技術分享

  註:用戶名密碼的驗證是在創建UserManager的時候配置的:

  技術分享

小結

  本文介紹了Owin以及ASP.NET MVC中是如何將Identity集成到Owin中並使用的,另外借鑒ASP.NET MVC模板的代碼改進了之前文章中的用戶註冊、登錄的實現。

參考:

  http://owin.org/html/spec/owin-1.0.html#1-overview
  https://msdn.microsoft.com/en-us/library/bb470252.aspx
  https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-middleware-in-the-iis-integrated-pipeline
  http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Host.SystemWeb/PreApplicationStart.cs

本文鏈接:http://www.cnblogs.com/selimsong/p/7743112.html

ASP.NET沒有魔法——目錄

ASP.NET沒有魔法——Identity與Owin