當某一個使用者使用使用者名稱成功登陸網站時,FormsAuthentication(表單身分識別驗證機制,下面統一使用英文術語) 將會建立一個authentication ticket (身分識別驗證票),通過這個ticket就可以在網站上全程跟蹤這個使用者了。Form authentication ticket通常被包含在一個Cookie裡面,但是Asp.net2.0也支援不使用Cookie的FormsAuthentication,這時候ticket就需要通過Query string 傳遞。
當一個使用者在登陸某個網站時,需要提供身分識別驗證才能進入網站。如果他還沒有輸入驗證資訊(通常是使用者名稱和密碼),則此使用者將會被重新導向到一個登陸頁面。使用者可以在登陸頁面輸入驗證資訊,然後這些資訊被發送到伺服器與某一個儲存使用者身份資訊的介質(例如Sql Server或者某個檔案)進行資訊對比。在ASP.Net2.0中,可以通過MemberShip Proivder來訪問儲存在諸如Sqlserver的資訊。(Provider模式有很多優點,稍後會有文章詳細說明。)當使用者資訊通過驗證後,此使用者將獲得允許,訪問他所期望的頁面。
FormsAuthentication通過FormsAuthenticationModule這個類來執行,這個類是ASP.net頁面運行周期的一部分。以下我們將解釋FormsAuthentication在ASP.net2.0中是如何工作的。
IIS 驗證
Asp.net驗證分為兩步。首先,IIS驗證目前使用者訪問網站所使用的windows帳號是否有許可權。如果IIS訪問被配置為anonymous,則任何使用者都能訪問頁面。
然後,在IIS驗證完畢後,ASP.net開始執行自身的驗證。驗證模式可以在web.config檔案中配置,只要在config檔案中寫上<authentication mode="Forms" />,那麼ASP.net就知道使用FormsAuthenticationModule 類進行驗證。
Asp.Net Froms Authentication
Froms Authentication 配置:你可以在config檔案中配置。配置如下:
<system.web>
<authentication mode="Forms">
<forms loginUrl="Login.aspx"
protection="All"
timeout="30"
name=".ASPXAUTH"
path="/"
requireSSL="false"
slidingExpiration="true"
defaultUrl="default.aspx"
cookieless="UseDeviceProfile" enableCrossAppRedirects="false" />
</authentication>
</system.web>
這些屬性詳細描述如下:
loginUrl:指向登陸頁面,你應改把登陸頁面放在一個需要Secure Sockets Layer (SSL)的檔案夾裡。這樣才能保障帳號的安全和完整。
potection:設定為”ALL”表明authentication ticket是加密的,密碼編譯演算法被定義在machineKey這個元素中,並且通過雜湊演算法進行簽名,這個演算法也定義在machineKey中。
timout:該屬性定義了驗證session的到期時間。預設值為30分鐘。
RequireSSL:該屬性被設定為false,這表明驗證的cookies可以不同過SSL加密傳輸。如果對session的安全性特別重視的話,則需要設定為true。
slidingExpiration:該屬性被設定為true,這表示使用者只要在網站上持續保持活動,則session就不會到期。
DefaultUrl:該屬性工作表示登陸後的預設頁面。
Cookieless:該屬性被設定為UseDeviceProfile,這表示cookie將在任何支援它的瀏覽器中使用,如果該瀏覽器不支援cookie的話,form authentication將通過url來傳遞authentication ticket
enableCrossAppRedirects:該屬性工作表示是否可以將通過身分識別驗證的使用者重新導向到其他web應用程式。True表示可以,False表示不可以。
Authorization Configuration(使用者配置)
類UrlAuthorizationModule用來執行保障只有通過身分識別驗證的使用者才能訪問頁面。你可以在web.config檔案中配置這個類:配置如下:
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
以上配置表明,沒有通過驗證的使用者都將被拒絕訪問頁面。如果一個沒有驗證的使用者試圖訪問頁面,他將會被重新導向到loginUrl屬性定義的登陸頁面上。
Forms Authentication 控制流程程
Forms Authentication的流程可以參考:
我們來分析一下上面的流程:
第一步:使用者訪問default.aspx頁面,IIS通過了驗證,ASP.Net發現 authorization
元素中包含<deny users="?" />的標籤。
第二步:伺服器尋找包含驗證資訊的cookie,如果沒有找到這個cookie,使用者將被重新導向到登陸頁面。就是loginurl所指定的頁面。使用者將在那個頁面輸入登陸資訊。:
第三步:瀏覽器請求瀏覽登入頁面,同時傳遞ReturnUrl的參數的值。
第四步:伺服器調轉到登陸頁面。
第五步:使用者輸入身分識別驗證資訊,並且提交資料,其中還包含ReturnUrl的參數值。
第六部:伺服器通過讀取儲存介質(例如sqserver資料庫)驗證使用者的資訊。登陸頁面將建立一個包含form authentication ticket的cookie作為session。
在Asp.net2.0身分識別驗證可以通過membership系統。Membership類提供了ValidateUser的方法,參考如下:
if (Membership.ValidateUser(userName.Text, password.Text))
{if (Request.QueryString["ReturnUrl"] != null) {FormsAuthentication.RedirectFromLoginPage(userName.Text,false); }
else { FormsAuthentication.SetAuthCookie(userName.Text, false); } }
else { Response.Write("Invalid UserID and Password");
}
第七步:使用者驗證成功,伺服器重新讓瀏覽器指向ReturUrl所指定的頁面。
第八步:在重新導向的同時,瀏覽器向default.aspx頁面發送request請求,此次請求包含使用者的forms authentication cookie。
第九步:FormsAuthenticationModule類偵測到forms authentication cookie並且開始驗證,驗證成功後,該類將得到當前的使用者資訊,並傳送給HttpContext對象。可以通過HttpContext對象獲得目前使用者的資訊。
第10步:驗證成功,來去自如哦!
FormsAuthenticationModule
ASP.Net 2.0在系統預設的web.config檔案中定義了一系列的Http模組(Http Modules).其中包括了一系列的驗證模組如下:
<httpModules>
...
<add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
<add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" /> ... </httpModules>
在每一次請求時,只能使用一種驗證模組。通常驗證模式會被定義在web.config檔案中:
<authentication mode="Forms" />這句話表示使用FormsAuthentication
FormsAuthenticationModule類會建立一個GenericPrincipal的對象,然後把它存入Http Context中。GenericPrincipal包含一個FormsIdentity的執行個體的引用,FormsIdentity執行個體包含了使用者的資訊。一般你會通過forms authentication來替你完成以上工作。但是如果你的程式還有別的特殊要求,比如把使用者資訊傳遞給一個自訂的類(該類繼承IPrincipal介面),你的程式需要在PostAuthenticate Event事件中編寫代碼。PostAuthenticate Event事件會在 FormsAuthenticationModule驗證forms authentication cookie 並且建立完GenericPrincipal和FormsIdentity對象後觸發,在該事件觸發後,你可以在事件中建立自訂的IPrincipal對象,用此對象封裝FormsIdentity對象,然後把自訂的IPrincipal對象存入HttpContext中。
注意:如果自訂IPricipal對象,你必須在當前線程中設定自訂對象的引用:例如:Thread.CurrentPrincipal=newGenericPrincipal(new GenericIdentity( "Bob", "Passport"), rolesArray);
這樣才能保證HttpContext對象和線程指向同一個驗證使用者的資訊。
Forms Authentication Cookies
FormsAuthentication類在調用FormsAuthentication.SetAuthCookie或者FormsAuthentication.RedirectFromLoginPage的方法後會自動建立驗證Cookie;
一個典型的驗證cookie包含以下兩個屬性:
Name:Cookie的名稱
Value:Cookie的值
在一個典型的forms authentication cookie中,cookie的值是加密的,並且建立一個FormAuthenticationTicket的簽名。Cookie包含以下屬性:
Expires:此屬性標識cookie的到期時間,當使用者需要把cookie儲存在本地電腦上時,需要設定此屬性。
Domain:這個屬性工作表明cookie和哪個域相關聯,預設的值為null
HasKeys:這個屬性工作表明cookie是否有子鍵。
HttpOnly: 這個屬性工作表示cookie是否能被用戶端指令碼讀取,.net2.0中,這個設定始終為true;但在用戶端瀏覽器中,只有IE6.0才能識別這個屬性。
Path:這個屬性工作表明cookie的虛擬目錄。預設的值為”/”,表示網站根目錄。
Secure:這個屬性工作表明cookie是否需要加密。如果設定true,cookie將接受SSL加密
Version:這個屬性工作表明cookie的版本號碼
建立Forms Authentication Cookies
當某個使用者驗證通過後,Forms Authentication Cookies會被Forms Authentication類在內部自動建立。建立的就是一個FormsAuthenticationTicket類。建立此類的代碼如下:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
"userName",
DateTime.Now,
DateTime.Now.AddMinutes(30), // value of time out property false, // Value of IsPersistent property
String.Empty,
FormsAuthentication.FormsCookiePath);
然後如果在web.config檔案中,forms元素的protection屬性被設定成ALL
或者Encryption,將對ticket對象進行加密並且建立簽名。加密代碼如下:
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
下面將簡要介紹一下當protection屬性被設定為true時的流程:
建立一個序列化的forms authentication ticket:即建立此對象為一個位元組數組(byte array)
建立forms authentication ticket的簽名。machineKey中的validation和alidationKey的屬性所設定了產生簽名的演算法。我們用此演算法計算上面序列化的bytearray,產生MAC(message authentication code)。在預設的選擇中,系統使用的是SHA1的演算法。
加密forms authentication ticket,同時我們將建立另外一個序列化的對象,此對象經過密碼編譯演算法加密。這個密碼編譯演算法也可在machineKey中的decryption和decryptionKey的屬性中獲得。在asp.net 1.1中使用的是3DES加密,而在asp.net2.0中,使用的是AES密碼編譯演算法。
建立HttpCookie對象或者產生cookie的query string,(在不支援cookie時,我們只能產生Query String).HttpCookie 對象建立方法代碼如下:
HttpCookie authCookie = new HttpCookie(
FormsAuthentication.FormsCookieName,
encryptedTicket);
加密後的ticket就被添加到了HttpCookie對象中。
設定forms authentication cookie為安全的。如果forms authentication ticket被配置成為使用SSL,那麼HttpCookie. Secure的屬性也必須設定成true.在這種情況下,瀏覽器只能通過HTTPS協議傳送Cookies.
設定HttpOnly bit,在asp.net2.0中,這個屬性預設設定完成。
設定當前cookie的屬性。如果需要,可以設定當前cookie的path, domain and和expires屬性
添加cookie至cookiecollection,傳給用戶端。Response.Cookies.Add(authCookie);
每當authentication收到一個請求,FormsAuthenticationModule從用戶端Cookie獲得一個authentication ticket,然後解碼,計算雜湊值比對MAC值,這樣就確認了cookie沒有被人為偽造。最後驗證ticket包含的到期時間。
注 ASP.NET 並不依賴於 Cookie 的到期日,因為該時間很容易偽造。
角色授權(Role Authorization)
在 ASP.NET 2.0 中,角色授權已經得到簡化。對使用者進行身分識別驗證或者將角色細節添加到身分識別驗證 Cookie 時,不再需要檢索角色資訊。.NET Framework 2.0 包括一個角色管理 API,它使您能夠建立和刪除角色,將使用者添加到角色以及從角色刪除使用者。該角色管理 API 將其資料存放區在一個基礎資料存放區中,它通過針對該資料存放區的適當角色提供者訪問該儲存。以下角色提供者為 .NET Framework 2.0 附帶,可以與表單身分識別驗證一起使用:
? SQL Server。它是預設的提供者,將角色資訊儲存在 SQL Server 資料庫。
? 授權管理員 (AzMan)。該提供者使用 XML 檔案、Active Directory 或 Active Directory 應用程式模式 (ADAM) 中的一個 AzMan 策略儲存作為其角色儲存。它通常用於 Intranet 或 Extranet 方案中,其中 Windows 身分識別驗證和 Active Directory 用於進行身分識別驗證。
How To: Use Role Manager in ASP.NET 2.0.
Cookieless表單驗證
ASP.NET 2.0 支援 cookieless 表單身分識別驗證。該功能由 forms 元素的 cookieless 屬性控制。該屬性可以設定為以下四個值之一:
? UseCookies。該值強制 FormsAuthenticationModule 類使用 Cookie 傳輸身分識別驗證票。
? UseUri。該值指示 FormsAuthenticationModule 類重寫 URL 來傳輸身分識別驗證票。
? UseDeviceProfile。該值指示 FormsAuthenticationModule 類查看瀏覽器功能。如果瀏覽器支援 Cookie,則使用 Cookie;否則,重寫 URL。
? AutoDetect。該值通過一個動態檢測機制指示 FormsAuthenticationModule 類檢測瀏覽器是否支援 Cookie。如果檢測邏輯表明不支援 Cookie,則重寫 URL。
如果應用程式配置為使用 cookieless 表單身分識別驗證,並且正在使用 FormsAuthentication.RedirectFromLoginPage 方法,則 FormsAuthenticationModule 類自動化佈建 URL 中的表單身分識別驗證票。以下程式碼範例顯示了典型 URL 在重寫後的外觀:
http://localhost/CookielessFormsAuthTest/(F(-k9DcsrIY4CAW81Rbju8KRnJ5o_gOQe0I1E_jNJLYm74izyOJK8GWdfoebgePJTEws0Pci7fHgTOUFTJe9jvgA2))/Test.aspx
括弧中的 URL 部分包含 Cookie 通常將包含的資料。該資料在請求處理過程中由 ASP.NET 刪除。該步驟由 ASP.NET ISAPI 篩選器執行,而不是在 HttpModule 類中執行。如果從一個 .aspx 頁讀取 Request.Path 屬性,您在 URL 中不會看到任何額外的資訊。如果重新導向請求,URL 將自動重寫。
注:難以保證 URL 中包含的身分識別驗證票的安全。當安全性極為重要時,您應該使用 Cookie 儲存身分識別驗證票。
MemberShip和LoginControl(成員資格和登入控制項)
ASP.NET 2.0 引入了MemberShip功能和一組登入 Web 伺服器控制項,它們簡化了使用表單身分識別驗證的應用程式的實現。
MemberShip為應用程式使用者提供憑據儲存和管理。它還提供一個MemberShip API,可以在使用表單身分識別驗證時簡化使用者憑證的驗證任務。該MemberShip功能構建於提供者模型之上。該模型允許實現和配置指向不同使用者儲存的不同提供者。ASP.NET 2.0 包括以下成員關係提供者:
? Active Directory membership provider。該提供者使用 Active Directory 或 Active Directory 應用程式模式 (ADAM) 使用者儲存。
? SQL Server membership provider。該提供者使用 SQL Server 使用者儲存。
還可以添加對自訂使用者儲存的支援。例如,可以添加對其他輕量級目錄訪問協議 (LDAP) 目錄或其他現有公用標識儲存的支援。為此,建立一個從 MembershipProvider 抽象基類繼承的自訂提供者。
ASP.NET 登入控制項自動使用MemberShip和表單身分識別驗證,並封裝提示使用者輸入憑據,驗證使用者,恢複或替換密碼等所需的邏輯。實際上,ASP.NET 登入控制項在表單身分識別驗證和MemberShip上提供一個抽象層,並且取代了您使用表單身分識別驗證時通常必須進行的大多數或全部工作。
Web Farm Scenarios(Web 場方案)
在 Web 場中,無法確保哪個伺服器將處理連續請求。如果使用者在一台伺服器上經過身分識別驗證,但下一個請求在另一台伺服器上進行,則身分識別驗證票將導致驗證失敗並請求使用者重新進行身分識別驗證。
machineKey 元素中的 validationKey 和 decryptionKey 屬性用於對表單身分識別驗證票進行雜湊操作和加密。這些屬性的預設值為 AutoGenerate.IsolateApps。這些密鑰是針對每個應用程式自動產生的,在每台伺服器上都不同。因此,在一台電腦上加密的身分識別驗證票無法在 Web 場中的另一台電腦或者同一台 Web 服務器上的另一個應用程式中進行解密和驗證。
為瞭解決該問題, Web 場中所有電腦上的 validationKey 和 decryptionKey 值都必須相同。