當(dāng)某一個(gè)用戶使用用戶名成功登陸網(wǎng)站時(shí),F(xiàn)ormsAuthentication(窗體身份驗(yàn)證機(jī)制,下面統(tǒng)一使用英文術(shù)語) 將會創(chuàng)建一個(gè)authentication ticket (身份驗(yàn)證票),通過這個(gè)ticket就可以在網(wǎng)站上全程跟蹤這個(gè)用戶了。Form authentication ticket通常被包含在一個(gè)Cookie里面,但是Asp.net2.0也支持不使用Cookie的FormsAuthentication,這時(shí)候ticket就需要通過Query string 傳遞。當(dāng)一個(gè)用戶在登陸某個(gè)網(wǎng)站時(shí),需要提供身份驗(yàn)證才能進(jìn)入網(wǎng)站。如果他還沒有輸入驗(yàn)證信息(通常是用戶名和密碼),則此用戶將會被重定向到一個(gè)登陸頁面。用戶可以在登陸頁面輸入驗(yàn)證信息,然后這些信息被發(fā)送到服務(wù)器與某一個(gè)存儲用戶身份信息的介質(zhì)(例如Sql Server或者某個(gè)文件)進(jìn)行信息對比。在ASP.Net2.0中,可以通過MemberShip Proivder來訪問存儲在諸如Sqlserver的信息。(Provider模式有很多優(yōu)點(diǎn),稍后會有文章詳細(xì)說明。)當(dāng)用戶信息通過驗(yàn)證后,此用戶將獲得允許,訪問他所期望的頁面。FormsAuthentication通過FormsAuthenticationModule這個(gè)類來執(zhí)行,這個(gè)類是ASP.net頁面運(yùn)行周期的一部分。以下我們將解釋FormsAuthentication在ASP.net2.0中是如何工作的。
Asp.net驗(yàn)證分為兩步。首先,IIS驗(yàn)證當(dāng)前用戶訪問網(wǎng)站所使用的windows賬號是否有權(quán)限。如果IIS訪問被配置為anonymous,則任何用戶都能訪問頁面。然后,在IIS驗(yàn)證完畢后,ASP.net開始執(zhí)行自身的驗(yàn)證。驗(yàn)證模式可以在web.config文件中配置,只要在config文件中寫上<authentication mode="Forms" />,那么ASP.net就知道使用FormsAuthenticationModule 類進(jìn)行驗(yàn)證。
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>這些屬性詳細(xì)描述如下:loginUrl:指向登陸頁面,你應(yīng)改把登陸頁面放在一個(gè)需要Secure Sockets Layer (SSL)的文件夾里。這樣才能保障賬號的安全和完整。potection:設(shè)置為”ALL”表明authentication ticket是加密的,加密算法被定義在machineKey這個(gè)元素中,并且通過哈希算法進(jìn)行簽名,這個(gè)算法也定義在machineKey中。timout:該屬性定義了驗(yàn)證session的過期時(shí)間。默認(rèn)值為30分鐘。RequireSSL:該屬性被設(shè)置為false,這表明驗(yàn)證的cookies可以不同過SSL加密傳輸。如果對session的安全性特別重視的話,則需要設(shè)置為true。slidingExpiration:該屬性被設(shè)置為true,這表示用戶只要在網(wǎng)站上持續(xù)保持活動(dòng),則session就不會過期。DefaultUrl:該屬性表示登陸后的默認(rèn)頁面。Cookieless:該屬性被設(shè)置為UseDeviceProfile,這表示cookie將在任何支持它的瀏覽器中使用,如果該瀏覽器不支持cookie的話,form authentication將通過url來傳遞authentication ticketenableCrossAppRedirects:該屬性表示是否可以將通過身份驗(yàn)證的用戶重定向到其他web應(yīng)用程序。True表示可以,F(xiàn)alse表示不可以。
類UrlAuthorizationModule用來執(zhí)行保障只有通過身份驗(yàn)證的用戶才能訪問頁面。你可以在web.config文件中配置這個(gè)類:配置如下:
<ystem.web><authorization><deny users="?" /></authorization></system.web>以上配置表明,沒有通過驗(yàn)證的用戶都將被拒絕訪問頁面。如果一個(gè)沒有驗(yàn)證的用戶試圖訪問頁面,他將會被重定向到loginUrl屬性定義的登陸頁面上。
Forms Authentication的流程可以參考下圖:我們來分析一下上面的流程:第一步:用戶訪問default.aspx頁面,IIS通過了驗(yàn)證,ASP.Net發(fā)現(xiàn) authorization元素中包含<deny users="?" />的標(biāo)簽。第二步:服務(wù)器尋找包含驗(yàn)證信息的cookie,如果沒有找到這個(gè)cookie,用戶將被重定向到登陸頁面。就是loginurl所指定的頁面。用戶將在那個(gè)頁面輸入登陸信息。:第三步:瀏覽器請求瀏覽登錄頁面,同時(shí)傳遞ReturnUrl的參數(shù)的值。第四步:服務(wù)器調(diào)轉(zhuǎn)到登陸頁面。第五步:用戶輸入身份驗(yàn)證信息,并且提交數(shù)據(jù),其中還包含ReturnUrl的參數(shù)值。第六部:服務(wù)器通過讀取存儲介質(zhì)(例如sqserver數(shù)據(jù)庫)驗(yàn)證用戶的信息。登陸頁面將創(chuàng)建一個(gè)包含form authentication ticket的cookie作為session。在Asp.net2.0身份驗(yàn)證可以通過membership系統(tǒng)。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");}第七步:用戶驗(yàn)證成功,服務(wù)器重新讓瀏覽器指向ReturUrl所指定的頁面。第八步:在重定向的同時(shí),瀏覽器向default.aspx頁面發(fā)送request請求,此次請求包含用戶的forms authentication cookie。第九步:FormsAuthenticationModule類偵測到forms authentication cookie并且開始驗(yàn)證,驗(yàn)證成功后,該類將得到當(dāng)前的用戶信息,并傳送給HttpContext對象??梢酝ㄟ^HttpContext對象獲得當(dāng)前用戶的信息。第10步:驗(yàn)證成功,來去自如哦!
ASP.Net 2.0在系統(tǒng)默認(rèn)的web.config文件中定義了一系列的Http模塊(Http Modules).其中包括了一系列的驗(yàn)證模塊如下:<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>在每一次請求時(shí),只能使用一種驗(yàn)證模塊。通常驗(yàn)證模式會被定義在web.config文件中:<authentication mode="Forms" />這句話表示使用FormsAuthenticationFormsAuthenticationModule類會創(chuàng)建一個(gè)GenericPrincipal的對象,然后把它存入Http Context中。GenericPrincipal包含一個(gè)FormsIdentity的實(shí)例的引用,F(xiàn)ormsIdentity實(shí)例包含了用戶的信息。一般你會通過forms authentication來替你完成以上工作。但是如果你的程序還有別的特殊要求,比如把用戶信息傳遞給一個(gè)自定義的類(該類繼承IPrincipal接口),你的程序需要在PostAuthenticate Event事件中編寫代碼。PostAuthenticate Event事件會在 FormsAuthenticationModule驗(yàn)證forms authentication cookie 并且創(chuàng)建完GenericPrincipal和FormsIdentity對象后觸發(fā),在該事件觸發(fā)后,你可以在事件中創(chuàng)建自定義的IPrincipal對象,用此對象封裝FormsIdentity對象,然后把自定義的IPrincipal對象存入HttpContext中。注意:如果自定義IPricipal對象,你必須在當(dāng)前線程中設(shè)置自定義對象的引用:例如:Thread.CurrentPrincipal=newGenericPrincipal(new GenericIdentity( "Bob", "Passport"), rolesArray);這樣才能保證HttpContext對象和線程指向同一個(gè)驗(yàn)證用戶的信息。
FormsAuthentication類在調(diào)用FormsAuthentication.SetAuthCookie或者FormsAuthentication.RedirectFromLoginPage的方法后會自動(dòng)創(chuàng)建驗(yàn)證Cookie;一個(gè)典型的驗(yàn)證cookie包含以下兩個(gè)屬性:Name:Cookie的名稱Value:Cookie的值在一個(gè)典型的forms authentication cookie中,cookie的值是加密的,并且創(chuàng)建一個(gè)FormAuthenticationTicket的簽名。Cookie包含以下屬性:Expires:此屬性標(biāo)識cookie的過期時(shí)間,當(dāng)用戶需要把cookie保存在本地電腦上時(shí),需要設(shè)置此屬性。Domain:這個(gè)屬性表明cookie和哪個(gè)域相關(guān)聯(lián),默認(rèn)的值為nullHasKeys:這個(gè)屬性表明cookie是否有子鍵。HttpOnly: 這個(gè)屬性表示cookie是否能被客戶端腳本讀取,.net2.0中,這個(gè)設(shè)置始終為true;但在客戶端瀏覽器中,只有IE6.0才能識別這個(gè)屬性。Path:這個(gè)屬性表明cookie的虛擬目錄。默認(rèn)的值為”/”,表示站點(diǎn)根目錄。Secure:這個(gè)屬性表明cookie是否需要加密。如果設(shè)置true,cookie將接受SSL加密Version:這個(gè)屬性表明cookie的版本號
當(dāng)某個(gè)用戶驗(yàn)證通過后,F(xiàn)orms Authentication Cookies會被Forms Authentication類在內(nèi)部自動(dòng)創(chuàng)建。創(chuàng)建的就是一個(gè)FormsAuthenticationTicket類。創(chuàng)建此類的代碼如下:FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,"userName",DateTime.Now,DateTime.Now.AddMinutes(30), // value of time out property false, // Value of IsPersistent propertyString.Empty,FormsAuthentication.FormsCookiePath);然后如果在web.config文件中,forms元素的protection屬性被設(shè)置成ALL或者Encryption,將對ticket對象進(jìn)行加密并且創(chuàng)建簽名。加密代碼如下:string encryptedTicket = FormsAuthentication.Encrypt(ticket);下面將簡要介紹一下當(dāng)protection屬性被設(shè)置為true時(shí)的流程:
- 創(chuàng)建一個(gè)序列化的forms authentication ticket:即創(chuàng)建此對象為一個(gè)字節(jié)數(shù)組(byte array)
- 創(chuàng)建forms authentication ticket的簽名。machineKey中的validation和alidationKey的屬性所設(shè)置了生成簽名的算法。我們用此算法計(jì)算上面序列化的bytearray,生成MAC(message authentication code)。在默認(rèn)的選擇中,系統(tǒng)使用的是SHA1的算法。
- 加密forms authentication ticket,同時(shí)我們將創(chuàng)建另外一個(gè)序列化的對象,此對象經(jīng)過加密算法加密。這個(gè)加密算法也可在machineKey中的decryption和decryptionKey的屬性中獲得。在asp.net 1.1中使用的是3DES加密,而在asp.net2.0中,使用的是AES加密算法。
- 創(chuàng)建HttpCookie對象或者生成cookie的query string,(在不支持cookie時(shí),我們只能生成Query String).HttpCookie 對象創(chuàng)建方法代碼如下:
HttpCookie authCookie = new HttpCookie(
FormsAuthentication.FormsCookieName,
encryptedTicket);
加密后的ticket就被添加到了HttpCookie對象中。- 設(shè)置forms authentication cookie為安全的。如果forms authentication ticket被配置成為使用SSL,那么HttpCookie. Secure的屬性也必須設(shè)置成true.在這種情況下,瀏覽器只能通過HTTPS協(xié)議傳送Cookies.
- 設(shè)置HttpOnly bit,在asp.net2.0中,這個(gè)屬性默認(rèn)設(shè)置完成。
- 設(shè)置當(dāng)前cookie的屬性。如果需要,可以設(shè)置當(dāng)前cookie的path, domain and和expires屬性
- 添加cookie至cookiecollection,傳給客戶端。Response.Cookies.Add(authCookie);
每當(dāng)authentication收到一個(gè)請求,F(xiàn)ormsAuthenticationModule從客戶端Cookie獲得一個(gè)authentication ticket,然后解碼,計(jì)算哈希值比對MAC值,這樣就確認(rèn)了cookie沒有被人為偽造。最后驗(yàn)證ticket包含的過期時(shí)間。注 ASP.NET 并不依賴于 Cookie 的到期日期,因?yàn)樵摃r(shí)間很容易偽造。
在 ASP.NET 2.0 中,角色授權(quán)已經(jīng)得到簡化。對用戶進(jìn)行身份驗(yàn)證或者將角色細(xì)節(jié)添加到身份驗(yàn)證 Cookie 時(shí),不再需要檢索角色信息。.NET Framework 2.0 包括一個(gè)角色管理 API,它使您能夠創(chuàng)建和刪除角色,將用戶添加到角色以及從角色刪除用戶。該角色管理 API 將其數(shù)據(jù)存儲在一個(gè)基礎(chǔ)數(shù)據(jù)存儲中,它通過針對該數(shù)據(jù)存儲的適當(dāng)角色提供程序訪問該存儲。以下角色提供程序?yàn)?.NET Framework 2.0 附帶,可以與窗體身份驗(yàn)證一起使用:
• SQL Server。它是默認(rèn)的提供程序,將角色信息存儲在 SQL Server 數(shù)據(jù)庫。
• 授權(quán)管理器 (AzMan)。該提供程序使用 XML 文件、Active Directory 或 Active Directory 應(yīng)用程序模式 (ADAM) 中的一個(gè) AzMan 策略存儲作為其角色存儲。它通常用于 Intranet 或 Extranet 方案中,其中 Windows 身份驗(yàn)證和 Active Directory 用于進(jìn)行身份驗(yàn)證。How To: Use Role Manager in ASP.NET 2.0.
ASP.NET 2.0 支持 cookieless 窗體身份驗(yàn)證。該功能由 forms 元素的 cookieless 屬性控制。該屬性可以設(shè)置為以下四個(gè)值之一:
• UseCookies。該值強(qiáng)制 FormsAuthenticationModule 類使用 Cookie 傳輸身份驗(yàn)證票。
• UseUri。該值指示 FormsAuthenticationModule 類重寫 URL 來傳輸身份驗(yàn)證票。
• UseDeviceProfile。該值指示 FormsAuthenticationModule 類查看瀏覽器功能。如果瀏覽器支持 Cookie,則使用 Cookie;否則,重寫 URL。
• AutoDetect。該值通過一個(gè)動(dòng)態(tài)檢測機(jī)制指示 FormsAuthenticationModule 類檢測瀏覽器是否支持 Cookie。如果檢測邏輯表明不支持 Cookie,則重寫 URL。如果應(yīng)用程序配置為使用 cookieless 窗體身份驗(yàn)證,并且正在使用 FormsAuthentication.RedirectFromLoginPage 方法,則 FormsAuthenticationModule 類自動(dòng)設(shè)置 URL 中的窗體身份驗(yàn)證票。以下代碼示例顯示了典型 URL 在重寫后的外觀:http://localhost/CookielessFormsAuthTest/(F(-k9DcsrIY4CAW81Rbju8KRnJ5o_gOQe0I1E_jNJLYm74izyOJK8GWdfoebgePJTEws0Pci7fHgTOUFTJe9jvgA2))/Test.aspx
括號中的 URL 部分包含 Cookie 通常將包含的數(shù)據(jù)。該數(shù)據(jù)在請求處理過程中由 ASP.NET 刪除。該步驟由 ASP.NET ISAPI 篩選器執(zhí)行,而不是在 HttpModule 類中執(zhí)行。如果從一個(gè) .aspx 頁讀取 Request.Path 屬性,您在 URL 中不會看到任何額外的信息。如果重定向請求,URL 將自動(dòng)重寫。注:難以保證 URL 中包含的身份驗(yàn)證票的安全。當(dāng)安全性極為重要時(shí),您應(yīng)該使用 Cookie 存儲身份驗(yàn)證票。
MemberShip為應(yīng)用程序用戶提供憑據(jù)存儲和管理。它還提供一個(gè)MemberShip API,可以在使用窗體身份驗(yàn)證時(shí)簡化用戶憑據(jù)的驗(yàn)證任務(wù)。該MemberShip功能構(gòu)建于提供程序模型之上。該模型允許實(shí)現(xiàn)和配置指向不同用戶存儲的不同提供程序。ASP.NET 2.0 包括以下成員關(guān)系提供程序:• Active Directory membership provider。該提供程序使用 Active Directory 或 Active Directory 應(yīng)用程序模式 (ADAM) 用戶存儲。• SQL Server membership provider。該提供程序使用 SQL Server 用戶存儲。還可以添加對自定義用戶存儲的支持。例如,可以添加對其他輕量級目錄訪問協(xié)議 (LDAP) 目錄或其他現(xiàn)有公共標(biāo)識存儲的支持。為此,創(chuàng)建一個(gè)從 MembershipProvider 抽象基類繼承的自定義提供程序。ASP.NET 登錄控件自動(dòng)使用MemberShip和窗體身份驗(yàn)證,并封裝提示用戶輸入憑據(jù),驗(yàn)證用戶,恢復(fù)或替換密碼等所需的邏輯。實(shí)際上,ASP.NET 登錄控件在窗體身份驗(yàn)證和MemberShip上提供一個(gè)抽象層,并且取代了您使用窗體身份驗(yàn)證時(shí)通常必須進(jìn)行的大多數(shù)或全部工作。有關(guān)使用MemberShip功能和登錄控件的詳細(xì)信息,請參閱How To: Use Membership in ASP.NET 2.0.
machineKey 元素中的 validationKey 和 decryptionKey 屬性用于對窗體身份驗(yàn)證票進(jìn)行哈希操作和加密。這些屬性的默認(rèn)值為 AutoGenerate.IsolateApps。這些密鑰是針對每個(gè)應(yīng)用程序自動(dòng)生成的,在每臺服務(wù)器上都不同。因此,在一臺計(jì)算機(jī)上加密的身份驗(yàn)證票無法在 Web 場中的另一臺計(jì)算機(jī)或者同一臺 Web 服務(wù)器上的另一個(gè)應(yīng)用程序中進(jìn)行解密和驗(yàn)證。為了解決該問題, Web 場中所有計(jì)算機(jī)上的 validationKey 和 decryptionKey 值都必須相同。有關(guān)配置 machineKey 元素的詳細(xì)信息,請參閱 How To: Configure MachineKey in ASP.NET 2.0