1. 程式人生 > >asp身份驗證問題

asp身份驗證問題

概述   窗體身份驗證使用使用者登入到站點時建立的身份驗證票,然後在整個站點內跟蹤該使用者。窗體身份驗證票通常包含在一個 Cookie 中。然而,ASP.NET 2.0 版支援無 Cookie 窗體身份驗證,結果是將票證傳入查詢字串中。   如果使用者請求一個需要經過身份驗證的訪問的頁,且該使用者以前沒有登入過該站點,則該使用者重定向到一個配置好的登入頁。該登入頁提示使用者提供憑據(通常是使用者名稱和密碼)。然後,將這些憑據傳遞給伺服器並針對使用者儲存(如 SQL Server 資料庫)進行驗證。在 ASP.NET 2.0 中,使用者儲存訪問可由成員身份提供程式處理。對使用者的憑據進行身份驗證後,使用者重定向到原來請求的頁面。   窗體身份驗證處理由 FormsAuthenticationModule
類實現,該類是一個參與常規 ASP.NET 頁處理迴圈的 HTTP 模組。本文闡釋 ASP.NET 2.0 中窗體身份驗證的工作機制。   IIS 身份驗證   ASP.NET 身份驗證分為兩個步驟。首先,Internet 資訊服務 (IIS) 對使用者進行身份驗證,並建立一個 Windows 令牌來表示該使用者。IIS 通過檢視 IIS 元資料庫設定,確定應該對特定應用程式使用的身份驗證模式。如果 IIS 配置為使用匿名身份驗證,則為 IUSR_MACHINE 帳戶生成一個令牌並用它表示匿名使用者。然後,IIS 將該令牌傳遞給 ASP.NET。   其次,ASP.NET 執行自己的身份驗證。所使用的身份驗證方法由 authentication
元素的 mode 屬性指定。以下身份驗證配置指定 ASP.NET 使用 FormsAuthenticationModule 類: <authentication mode="Forms" />    由於窗體身份驗證不依賴於 IIS 身份驗證,因此如果要在 ASP.NET 應用程式中使用窗體身份驗證,則應該在 IIS 中為應用程式配置匿名訪問。   ASP.NET 窗體身份驗證   ASP.NET 窗體身份驗證在 IIS 身份驗證完成後發生。可以使用 forms 元素配置窗體身份驗證。   窗體身份驗證配置   以下配置檔案片段顯示窗體身份驗證的預設屬性值。
<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 指向應用程式的自定義登入頁。應該將登入頁放在需要安全套接字層 (SSL) 的資料夾中。這有助於確保憑據從瀏覽器傳到 Web 伺服器時的完整性。
· protection 設定為 All,以指定窗體身份驗證票的保密性和完整性。這導致使用 machineKey 元素上指定的演算法對身份驗證票證進行加密,並且使用同樣是 machineKey 元素上指定的雜湊演算法進行簽名。
· timeout 用於指定窗體身份驗證會話的有限生存期。預設值為 30 分鐘。如果頒發持久的窗體身份驗證 Cookie,timeout 屬性還用於設定持久 Cookie 的生存期。
· namepath 設定為應用程式的配置檔案中定義的值。
· requireSSL 設定為 false。該配置意味著身份驗證 Cookie 可通過未經 SSL 加密的通道進行傳輸。如果擔心會話竊取,應考慮將 requireSSL 設定為 true
· slidingExpiration 設定為 true 以執行變化的會話生存期。這意味著只要使用者在站點上處於活動狀態,會話超時就會定期重置。
· defaultUrl 設定為應用程式的 Default.aspx 頁。
· cookieless 設定為 UseDeviceProfile,以指定應用程式對所有支援 Cookie 的瀏覽器都使用 Cookie。如果不支援 Cookie 的瀏覽器訪問該站點,窗體身份驗證在 URL 上打包身份驗證票。
· enableCrossAppRedirects 設定為 false,以指明窗體身份驗證不支援自動處理在應用程式之間傳遞的查詢字串上的票證以及作為某個窗體 POST 的一部分傳遞的票證。

  授權配置   在 IIS 中,對所有使用窗體身份驗證的應用程式啟用非同步訪問。UrlAuthorizationModule 類用於幫助確保只有經過身份驗證的使用者才能訪問頁。   可以使用 authorization 元素配置 UrlAuthorizationModule,如以下示例所示。

<system.web>   <authorization>     <deny users="?" />   </authorization> </system.web> 

  使用該設定將拒絕所有未經過身份驗證的使用者訪問應用程式中的任何頁。如果未經身份驗證的使用者試圖訪問某頁,窗體身份驗證模組將該使用者重定向到 forms 元素的 loginUrl 屬性指定的登入頁。   窗體身份驗證控制流   圖 1 顯示窗體身份驗證期間出現的事件順序。 1. 窗體身份驗證控制流

· 使用者請求應用程式的虛擬目錄下的 Default.aspx 檔案。因為 IIS 元資料庫中啟用了匿名訪問,因此 IIS 允許該請求。ASP.NET 確認 authorization 元素包括 <deny users="?" /> 標記。
· 伺服器查詢一個身份驗證 Cookie。如果找不到該身份驗證 Cookie,則使用者重定向到配置好的登入頁 (Login.aspx),該頁由 forms 元素的 LoginUrl 屬性。使用者通過該窗體提供和提交憑據。有關起始頁的資訊存放在使用 RETURNURL 作為金鑰的查詢字串中。伺服器 HTTP 應答如下所示:
302 Found Location:  http://localhost/FormsAuthTest/login.aspx?RETURNURL=%2fFormAuthTest%2fDefault.aspx 
· 瀏覽器請求 Login.aspx 頁,並在查詢字串中包括 RETURNURL 引數。
· 伺服器返回登入頁以及 200 OK HTTP 狀態程式碼。
· 使用者在登入頁輸入憑據,並將該頁(包括來自查詢字串的 RETURNURL 引數)傳送回伺服器。
· 伺服器根據某個儲存(如 SQL Server 資料庫或 Active Directory 使用者儲存)驗證使用者憑據。登入頁中的程式碼建立一個包含為該會話設定的窗體身份驗證票的 Cookie。 在 ASP.NET 2.0 中,可以通過成員身份系統執行對使用者憑據的驗證。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"); } 
使用 Login Web 伺服器控制元件時,它自動為您執行以下步驟。下文使用了前面提供的程式碼。
· 對於經過身份驗證的使用者,伺服器將瀏覽器重定向到查詢字串中的 RETURNURL 引數指定的原始 URL。伺服器 HTTP 應答如下所示:
302 Found Location:  http://localhost/TestSample/default.aspx 
· 重定向之後,瀏覽器再次請求 Default.aspx 頁。該請求包括身份驗證 Cookie。
· FormsAuthenticationModule 類檢測窗體身份驗證 Cookie 並對使用者進行身份驗證。身份驗證成功後,FormsAuthenticationModule 類使用有關經過身份驗證的使用者的資訊填充當前的 User 屬性(由 HttpContext 物件公開)。
· 由於伺服器已經驗證了身份驗證 Cookie,因此它允許訪問並返回 Default.aspx 頁。
  FormsAuthenticationModule   ASP.NET 2.0 在計算機級 Web.config 檔案中定義了一組 HTTP 模組,包括大量身份驗證模組,如下所示:
<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> 

  每個請求只能使用一個身份驗證模組。所使用的身份驗證模組取決於 authentication 元素(通常位於應用程式的虛擬目錄中的 Web.config 檔案中)指定了哪種身份驗證模式。   當 Web.config 檔案中包含以下元素時,啟用 FormsAuthenticationModule 類。

<authentication mode="Forms" /> 

  FormsAuthenticationModule 類構造一個 GenericPrincipal 物件並將其儲存在 HTTP 上下文中。GenericPrincipal 物件儲存對一個 FormsIdentity 例項的引用,該例項代表當前經過身份驗證的使用者。應該允許窗體身份驗證為您管理這些任務。如果應用程式有特定要求(例如,將 User 屬性設定為一個實現 IPrincipal 介面的自定義類),則該應用程式應該處理 PostAuthenticate 事件。FormsAuthenticationModule 驗證了窗體身份驗證 Cookie 並建立了 GenericPrincipalFormsIdentity 物件之後,會發生 PostAuthenticate 事件。在該程式碼中,可以構造一個包裝 FormsIdentity 物件的自定義 IPrincipal 物件,然後將它儲存在 HttpContext. User 屬性中。   注 如果執行了這一操作,還需要設定 Thread.CurrentPrincipal 屬性上的 IPrincipal 引用,以確保 HttpContext 物件和該執行緒指向相同的身份驗證資訊。

  窗體身份驗證 Cookie   呼叫 FormsAuthentication.SetAuthCookieFormsAuthentication.RedirectFromLoginPage 方法時,FormsAuthentication 類自動建立身份驗證 Cookie。   典型的窗體身份驗證 Cookie 中包括以下屬性:

· Name。該屬性指定 Cookie 的名稱。
· Value。該屬性指定 Cookie 的值。 在典型的窗體身份驗證 Cookie 中,該值包含一個經過加密和簽名的 FormsAuthenticationTicket 物件的字串表示形式。該 Cookie 包含以下屬性:
· Expires。該屬性指定 Cookie 的到期日期和時間。僅當代碼指示應該頒發一個持久的窗體身份驗證 Cookie,窗體身份驗證才設定該值。
· Domain。該屬性指定與 Cookie 關聯的域。預設值為 null
· HasKeys。該屬性指出 Cookie 是否有子項。
· HttpOnly。該屬性指定是否可以通過客戶端指令碼訪問該 Cookie。在 ASP.NET 2.0 中,該值始終設定為 true。Internet Explorer 6 Service Pack 1 支援該 Cookie 屬性,從而防止客戶端指令碼從 document.cookie 屬性訪問該 Cookie。如果嘗試從客戶端指令碼訪問該 Cookie,則返回一個空字串。無論何時使用者瀏覽到當前域中的 Web 站點,該 Cookie 仍然傳送至伺服器。 不支援 HttpOnly Cookie 屬性的 Web 瀏覽器要麼忽略該 Cookie,要麼忽略該屬性,這意味著會話仍然容易受到跨站點指令碼的攻擊。
· Path。該屬性指定 Cookie 的虛擬路徑。預設值為"/",代表根目錄。
· Secure。該屬性指出 Cookie 是否應該僅通過 HTTPS 連線傳輸。Secure 屬性應設定為 true,以便該 Cookie 可以受 SSL 加密的保護。
· Version。該屬性指定 Cookie 的版本號。
  建立身份驗證 Cookie   通過 FormsAuthentication 類建立身份驗證 Cookie,如下所示。使用者經過驗證後,FormsAuthentication 類在內部建立一個 FormsAuthenticationTicket 物件,方法是指定 Cookie 名、Cookie 版本、目錄路徑、Cookie 頒發日期;Cookie 到期日期、是否應該保留 Cookie,以及使用者定義的資料(可選)。
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);    

  接下來,如果 forms 元素的 protection 屬性設定為 AllEncryption,則窗體身份驗證使用 Encrypt 方法對窗體身份驗證票進行加密和簽名。

string encryptedTicket = FormsAuthentication.Encrypt(ticket);    

  以下文字顯示了當 protection 屬性設定為 All 時使用的過程:

· 建立序列化窗體身份驗證票。建立票證的位元組陣列表示形式。
· 對窗體身份驗證票進行簽名。位元組陣列的訊息身份驗證程式碼 (MAC) 的值,由使用 machineKey 元素的 validationvalidationKey 屬性指定的演算法和金鑰進行計算。預設情況下,使用 SHA1 演算法。
· 對窗體身份驗證票進行加密。已經建立的第二個位元組陣列使用 FormsAuthentication 類的 Encrypt 方法進行加密。該 Encrypt 方法在內部使用由 machineKey 元素上的 decryptiondecryptionKey 屬性指定的演算法和金鑰。ASP.NET 1.1 版在預設情況下使用 3DES 演算法。ASP.NET 2.0 版在預設情況下使用 Rinjdael (AES) 演算法。
· 根據需要建立 HTTP Cookie 或查詢字串。然後,如果窗體身份驗證針對 cookieless 身份驗證進行了配置,則加密的身份驗證票新增到 HttpCookie 物件。使用以下程式碼建立該 Cookie 物件:
HttpCookie authCookie = new HttpCookie(                             FormsAuthentication.FormsCookieName,                              encryptedTicket); 
· 將窗體身份驗證Cookie 設定為安全的。如果窗體身份驗證票配置為使用 SSL,則 HttpCookie.Secure 屬性設定為 true。這表明瀏覽器僅通過 HTTPS 連線傳送 Cookie。
authCookie.Secure = true; 
· 設定 HttpOnly 。在 ASP.NET 2.0 中,始終設定該位。
· 設定適當的 Cookie 屬性。如果需要,設定 Cookie 的 pathdomainexpires 屬性。
· Cookie 新增到 Cookie 集合。將身份驗證 Cookie 新增到要返回給客戶端瀏覽器的 Cookie 集合。
Response.Cookies.Add(authCookie); 
  每次在身份驗證之後接收一個後續請求時,FormsAuthenticationModule 類都會從身份驗證 Cookie 中檢索身份驗證票,對其進行解密,計算雜湊值,並比較該 MAC 值,以幫助確保該 Cookie 未被篡改。最後,驗證該窗體身份驗證票中包含的到期時間。   注 ASP.NET 並不依賴於 Cookie 的到期日期,因為該時間很容易偽造。

  角色授權   在 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 用於進行身份驗證。
  有關如何使用角色管理 API 的詳細資訊,請參閱 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_jNJLYm74izyOJK8GWdfoebgePJTEws0
_Pci7fHgTOUFTJe9jvgA2))/Test.aspx 

  括號中的 URL 部分包含 Cookie 通常將包含的資料。該資料在請求處理過程中由 ASP.NET 刪除。該步驟由 ASP.NET ISAPI 篩選器執行,而不是在 HttpModule 類中執行。如果從一個 .aspx 頁讀取 Request.Path 屬性,您在 URL 中不會看到任何額外的資訊。如果重定向請求,URL 將自動重寫。   注 難以保證 URL 中包含的身份驗證票的安全。當安全性極為重要時,您應該使用 Cookie 儲存身份驗證票。   成員身份和登入控制元件   ASP.NET 2.0 引入了成員身份功能和一組登入 Web 伺服器控制元件,它們簡化了使用窗體身份驗證的應用程式的實現。   成員身份為應用程式使用者提供憑據儲存和管理。它還提供一個成員身份 API,可以在使用窗體身份驗證時簡化使用者憑據的驗證任務。該成員身份功能構建於提供程式模型之上。該模型允許實現和配置指向不同使用者儲存的不同提供程式。ASP.NET 2.0 包括以下成員關係提供程式:

· Active Directory 成員關係提供程式。該提供程式使用 Active Directory 或 Active Directory 應用程式模式 (ADAM) 使用者儲存。
· SQL Server 成員關係提供程式。該提供程式使用 SQL Server 使用者儲存。
  還可以新增對自定義使用者儲存的支援。例如,可以新增對其他輕量級目錄訪問協議 (LDAP) 目錄或其他現有公共標識儲存的支援。為此,建立一個從 MembershipProvider 抽象基類繼承的自定義提供程式。   ASP.NET 登入控制元件自動使用成員身份和窗體身份驗證,並封裝提示使用者輸入憑據,驗證使用者,恢復或替換密碼等所需的邏輯。實際上,ASP.NET 登入控制元件在窗體身份驗證和成員身份上提供一個抽象層,並且取代了您使用窗體身份驗證時通常必須進行的大多數或全部工作。   Web 場方案   在 Web 場中,無法確保哪個伺服器將處理連續請求。如果使用者在一臺伺服器上經過身份驗證,但下一個請求在另一臺伺服器上進行,則身份驗證票將導致驗證失敗並請求使用者重新進行身份驗證。   machineKey 元素中的 validationKeydecryptionKey 屬性用於對窗體身份驗證票進行雜湊操作和加密。這些屬性的預設值為 AutoGenerate.IsolateApps。這些金鑰是針對每個應用程式自動生成的,在每臺伺服器上都不同。因此,在一臺計算機上加密的身份驗證票無法在 Web 場中的另一臺計算機或者同一臺 Web 伺服器上的另一個應用程式中進行解密和驗證。   為了解決該問題, Web 場中所有計算機上的 validationKeydecryptionKey 值都必須相同。有關配置 machineKey 元素的詳細資訊。