天天看點

ASP.NET Forms驗證詳解

建立網站中,常常會使用到身份驗證。asp.net中内置了幾種身份驗證的方式,如Windows、Froms、Passport等。這幾種身份驗證的方式各有不同。一般來說,網站的身份驗證方式都會經過以下幾個步驟:

    1、輸入使用者名和密碼,單擊确定按鈕。

    2、在背景判斷使用者名和密碼是否正确,如果錯誤傳回提示;如果正确,進入可通路的頁面。

    在ASP時代,通常都會在驗證使用者名和密碼是否比對之後,建立一個Session,然後在每個需要驗證的頁面中判斷Session是否存在,如果存在,則顯示頁面内容;如果不存在,産生提示,并跳轉到登入頁面。

    但是,在asp.net時代,這個過程就給大大的減化了,不再需要在每個需要驗證的頁面中去校驗Session,隻需要進行如下幾步,就可以完成身份驗證過程。

    第一步:修改web.config檔案。

    1、在<system.web>和</system.web>中找到<authentication>節,将其改為“<authentication mode="Forms" />”,其中Forms代表使用表單認證。

    2、<system.web>和</system.web>中添加“<authorization><deny users="?"/></authorization>”,其中“<deny users="?"/>”代表拒絕所有的匿名使用者。

    第二步:建立login.aspx檔案。

    在經過第一步之後,無論使用者通路網站中的哪個檔案,隻要沒有經過身份驗證,asp.net會自動跳轉到login.aspx網頁上,并且在URL中使用ReturnUrl參數來傳遞使用者目前通路的網頁。

    假設使用者沒有經過身份驗證就直接通路test.aspx檔案,那麼asp.net會自動跳轉了login.aspx網頁,此時浏覽器視窗中的位址欄中的URL為:“login.aspx?ReturnUrl=%2ftest.aspx”,是以,可以在身份驗證通過後,再将網頁跳回到ReturnUrl參數指定的網頁上去。

    第三步:在login.aspx檔案中驗證身份。

    身份驗證方式比較簡單,一般都是建立一個文本框和一個密碼框,使用者輸入使用者名和密碼後,單擊送出按鈕,則去資料庫中驗證身份,詳細過程就不寫了,在此隻要輸入的使用者名為1,密碼為2就認為身份驗證通過。

    身份驗證完畢之後,使用FormsAuthentication.SetAuthCookie()為使用者建立一個身份驗證的票據,并将其添加到Cookie中。以後,再通路網站中的其他網頁,就不需要使用進行身份驗證了。單擊送出按鈕後的代碼如下所示。

[c-sharp]  view plain copy

  1. protected void Button1_Click(object sender, EventArgs e)  
  2. {  
  3.     //身份驗證方式,本例中使用者名為1,密碼為2  
  4.     if (TextBox1.Text == "1" && TextBox2.Text == "2")  
  5.     {  
  6.         FormsAuthentication.SetAuthCookie(TextBox1.Text, false);  
  7.     }  
  8.     //如果URL中沒有傳遞ReturnUrl參數,則跳轉到Default.aspx,否則跳轉到ReturnUrl參數值指定的網頁  
  9.     if (string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))  
  10.     {  
  11.         Response.Redirect("Default.aspx");  
  12.     }  
  13.     else  
  14.     {  
  15.         Response.Redirect(Request.QueryString["ReturnUrl"].ToString());  
  16.     }  
  17. }  
  18. 在上一篇博文《asp.net中的窗體身份驗證(最簡單篇)》中的身份驗證雖然很簡單,但是有一個缺點,就是通路整個網站都必須要經過身份驗證,而事實上,很多網站都不會這麼要求的。

        比如一個新聞系統,通常隻有在釋出新聞的網頁才需要身份驗證,而使用者浏覽新聞是不需要身份驗證的。對于這種情況,就要針對不同的網頁來進行身份驗證了。

        要實作這種功能,也隻要将《asp.net中的窗體身份驗證(最簡單篇)》稍作修改,具體操作方式如下所示:

        第一步、建立一個子檔案夾,将所有要驗證的網頁都放在這個檔案夾中,設定該檔案夾的名字為“admin”。

        第二步、修改web.config檔案。

        1、在<system.web>和</system.web>中找到<authentication>節,将其改為“<authentication mode="Forms"><forms loginUrl="~/admin/AdminLogin.aspx"></forms></authentication>”,其中Forms代表使用表單認證;loginUrl用于指定登入頁面URL,個人比較喜歡将登入頁面也放在admin檔案夾中,是以在此要指定登入頁面URL,如果還是想使用根目錄中的login.aspx頁面作為登入頁面,則可以省略<forms>節。

        2、在<system.web>和</system.web>中添加“<authorization><allow users="?"/></authorization>”,其中“<allow users="?"/>”代表允許所有的匿名使用者。注意此處與《asp.net中的窗體身份驗證(最簡單篇)》的差別,在《asp.net中的窗體身份驗證(最簡單篇)》中,此處使用的是“<deny users="?"/>”,用于拒絕所有匿名使用者。

        第三步、在需要身份驗證的子檔案夾中添加一個web.config檔案,在本例中為在“admin”檔案夾中添加該檔案。

        第四步、修改需要身份驗證的子檔案夾中的web.config檔案,在本例中為“admin”檔案夾中的web.config檔案。

        在<system.web>和</system.web>中,添加“<authorization><deny users="?"/></authorization>”,由于在根目錄中的web.config檔案中聲明了允許所有匿名使用者通路,是以在不能允許匿名使用者通路的子檔案夾中,必須要使用“<deny users="?"/>”來拒絕匿名使用者通路。另外,在子檔案夾中的web.config檔案中可以沒有<authentication>節。

        第五步、在“admin”子檔案夾中建立AdminLogin.aspx檔案。如果在第二步中沒有使用<forms>節來指定使用者登入頁面,則在網站根目錄下建立login.aspx檔案。

        第六步、在AdminLogin.aspx檔案(或login.aspx檔案)中驗證身份,如果身份驗證通過,使用FormsAuthentication.SetAuthCookie()為使用者建立一個身份驗證的票據,并将其添加到Cookie中。以後,再通路網站中admin子目錄下的其他網頁,就不需要使用進行身份驗證了。單擊送出按鈕後的代碼與《asp.net中的窗體身份驗證(最簡單篇)》中的代碼類似,在此就不再贅述了。

    在《asp.net中的窗體身份驗證(最簡單篇) 》中介紹了使用FormsAuthentication.SetAuthCookie()方法建立身份驗證票據的方法,事實上,這是一個使用預設的身份驗證票據的方法。在asp.net中,Forms身份驗證的方式是在使用者登入時建立一個身份驗證票,然後将這個身份驗證票存放在Cookie中,以後整個網站都可以通過這個Cookie來判斷使用者是否已經登入。如果使用者浏覽器不支援Cookie,asp.net也可以将票證放在URL的查詢字元串中進行傳遞,這個不是本文的 重點,也就不詳細介紹了。

        那麼當通路一個asp.net的網站時,asp.net究竟是怎麼進行身份驗證的呢?

        在asp.net中,将身份驗證分成了兩個部分,第一個部分是IIS的身份驗證,在使用者通路網站時,IIS首先就會對使用者進行身份驗證,這個身份驗證的具體設定在IIS中,這也非本文的重點,在此也不再詳細介紹了。隻有IIS通過了使用者的身份驗證之後,才會進行第二個部分的身份驗證,這個部分的身份驗證則由asp.net來完成。

        asp.net的身份驗證方式由web.config檔案中的<authentication>節點的mode屬性值設定,如果要使用Forms身份驗證,mode屬性值必須為Forms。

        設定完<authentication>節點的mode屬性值之後,我們還可以在該節點下添加一個<forms>節點,用于說明Forms身份驗證的具體選項。常用的<authentication>節點的設定方式如下所示:

    [c-sharp]  view plain copy

    1. <authentication mode="Forms">  
    2.  <forms   
    3.    loginUrl="AdminLogin.aspx"  
    4.    timeout="30"   
    5.    name=".ASPXAUTH"   
    6.    path="/"   
    7.    requireSSL="false"   
    8.    cookieless="UseDeviceProfile"   
    9.    defaultUrl="default.aspx"   
    10.    slidingExpiration="true"   
    11.    protection="All"   
    12.    enableCrossAppRedirects="false">  
    13.  </forms>  
    14. </authentication>   

        以上代碼中,loginUrl為使用者登入網頁,如果省略,asp.net将使用網站根目錄下的login.aspx為登入頁面。timeout設定登入逾時時間為30分鐘。name為存儲身份驗證票據的Cookie名,預設值為“.ASPXAUTH” 。path為存儲身份驗證票據的Cookie的路徑,預設值為“/”。requireSSL為存儲身份驗證票據的Cookie是否使用SSL加密傳輸,預設為false。cookieless為浏覽器不支援Cookie時的存儲身份驗證票據的傳遞方式,預設值為“UseDeviceProfile”,即自動檢測浏覽器是否支援Cookie,如果浏覽器支援Cookie則使用Cookie傳遞身份驗證票據,如果浏覽器不支援Cookie則使用URL傳遞身份驗證票據。defaultUrl為登入後預設跳轉的網頁,預設值為“default.aspx”。slidingExpiration為是否以執行可變的會話生存期,預設值為true。protection為Cookie的加密類型,預設值為“All”,即對Cookie同時使用資料驗證和加密方法,其中資料驗證算法由<machineKey>節點中設定。enableCrossAppRedirects是否将通過身份驗證的使用者重新定向到其它Web應用程式的URL中,預設值為false。

        在以上代碼中,<forms>節點中的protection屬性值為All,說明要對Cookie同時使用資料驗證和加密方法,而資料驗證算法由<machineKey>節點中設定,這就意味着要在<system.web>節點下添加一個<machineKey>子節點。<machineKey>節點的作用是對密鑰進行設定,如以下代碼所示:

    [c-sharp]  view plain copy

    1. <machineKey validation="3DES"/>  

      <authentication>節點用于設定asp.net的身份驗證方式,也就是要怎麼去驗證使用者身份,但驗證完使用者身份之後,哪些使用者可以通路資源,<authentication>節點就不能進行設定了,這個使用就 必須要使用到<authorization>節點,該節點可以設定應用程式的授權,隻有授權的使用者才能通路網站資源。

        <authorization>節點下面可以有兩種子節點:<allow>和<deny>。其中<allow>節點用于說明允許對網站資源通路的規則。<deny>節點用于說明禁止對網站資源通路的規則。

        拒絕匿名使用者通路的設定方式如下所示:

    [c-sharp]  view plain copy

    1. <authorization>  
    2.     <deny users="?"/>  
    3. </authorization>>  

         經過以上幾個步驟,web.config檔案的修改基本上就結束了,一個完整的web.config檔案如下所示:

    [c-sharp]  view plain copy

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <configuration>  
    3.     <appSettings/>  
    4.     <connectionStrings/>  
    5.     <system.web>  
    6.       <compilation debug="true" />  
    7.             <authentication mode="Forms">  
    8.                 <forms   
    9.                      loginUrl="AdminLogin.aspx"  
    10.                      timeout="30"   
    11.                      name=".ASPXAUTH"   
    12.                      path="/"   
    13.                      requireSSL="false"   
    14.                      cookieless="UseDeviceProfile"   
    15.                      defaultUrl="default.aspx"   
    16.                      slidingExpiration="true"   
    17.                      protection="All"   
    18.                      enableCrossAppRedirects="false">  
    19.                 </forms>  
    20.             </authentication>  
    21.             <authorization>  
    22.                 <deny users="?"/>  
    23.             </authorization>  
    24.             <machineKey validation="3DES"/>  
    25.     </system.web>  
    26. </configuration>  

        至此為止,網站窗體身份驗證方式就已經建立完畢,此時,無法通路網站中的哪個網頁,都會自動跳轉到AdminLogin.aspx頁面,下一步可以編寫AdminLogin.aspx網頁代碼了。

        本文中涉及到的web.confing檔案中的節點的詳細解釋可以在《asp.net中的窗體身份驗證(完整篇之附錄:web.config中相應節點詳解)》中查閱。

    在《asp.net中的窗體身份驗證(完整篇之一:建立asp.net的窗體身份驗證方式) 》中介紹了如何通過修改web.config檔案來建立窗體身份驗證。修改完web.config檔案之後,網站就可以使用窗體身份驗證方式來驗證使用者身份了。那麼,整個身份驗證的過程是怎麼樣的呢?

        前面說過,在asp.net中,身份驗證過程分為兩部分,一部分是IIS中的身份驗證,隻有通過了IIS中的身份驗證之後,才行進行asp.net中的身份驗證。一個完整的窗體身份驗證流程如下所示:

    1. 首先,使用者通過浏覽器向伺服器發送一個網頁請求,假設使用者要通路index.aspx網頁, 那麼浏覽器就會将請求發送給IIS伺服器。
    2. 假設在該伺服器中将IIS設定成可以匿名通路,那麼IIS伺服器将會允許通路index.aspx網頁。
    3. IIS伺服器允許通路之後,将會進入asp.net身份驗證。asp.net會去web.config檔案中檢視<authorization>節點下的<deny>節點中是否拒絕所有匿名使用者。如果拒絕了所有匿名使用者,伺服器則會去查找一個身份驗證的Cookie。
    4. 如果伺服器查找不到該身份驗證的Cookie,就會将網頁跳轉到登入頁面。這個登入頁面為<forms>節點中的loginUrl屬性值,預設為網站根目錄下的login.aspx。在跳轉到到登入頁面時,伺服器會将目前通路的網頁的位址,如index.aspx,作為ReturnUrl參數值附加到login.aspx的URL中。如下所示:

      login.aspx?ReturnUrl=%2findex.aspx

    5. 使用者在登入頁面輸入使用者名和密碼(或别的登入資訊),并将這些資訊送出到伺服器。
    6. 伺服器接收到使用者送出的資訊之後,判斷使用者是否為合法使用者(判斷方式有很多種,但這不是本文的重點),如果使用者為合法使用者,則建立一個包含窗體身份驗證票的Cookie。
    7. 在建立完包含窗體身份驗證票的Cookie之後,可以使用代碼将網頁跳回登入前通路的頁面,如index.aspx網頁(這個時侯ReturnUrl參數就起作用了)。
    8. 在登入後通路其它網頁時(如跳轉後的index.aspx頁面),伺服器會檢測包含窗體身份驗證的Cookie,并對使用者進行身份驗證。身份驗證成功後,伺服器傳回使用者需要通路的網頁。

        以上就是一個完整的asp.net窗體身份驗證流程,下面将會介紹如何按着該流程來編寫asp.net代碼。

    在《asp.net中的窗體身份驗證(完整篇之二:asp.net的窗體身份驗證過程) 》中我們介紹了asp.net的窗體身份驗證過程,按照這個流程,我們可以開始動手編寫網頁代碼。根據《asp.net中的窗體身份驗證(完整篇之一:建立asp.net的窗體身份驗證方式) 》中的web.config代碼,我們網站的登入頁面為AdminLogin.aspx。在沒有登入的情況下,如果通路Default.aspx網頁,伺服器會自動跳轉到AdminLogin.aspx,如下圖所示。

    ASP.NET Forms驗證詳解

        從上圖中可以看出,浏覽器位址欄中,AdminLogin.aspx後有參數ReturnUrl,而ReturnUrl的值跳轉之間通路的Default.aspx網頁。

        在上圖所示頁面中,使用者可以輸入使用者名和密碼,然後單擊登入按鈕送出資訊。在背景,伺服器接收到使用者送出的資訊後,可以判斷使用者送出的使用者和密碼是否比對,如果比對,則認為身份驗證通過。這個時候,進入了《asp.net中的窗體身份驗證(完整篇之二:asp.net的窗體身份驗證過程) 》中的第6步,也就是“建立一個包含窗體身份驗證票的Cookie”。

        所謂“建立一個包含窗體身份驗證票的Cookie”,事實上是分兩步走,第一步是建立一個窗體身份驗證票,第二步是将身份驗證票放在Cookie中。不過呢,在asp.net中,可以簡化這個過程。

        方式一:使用預設的身份驗證票。這個時候單擊登入按鈕的代碼如下所示:

    [c-sharp]  view plain copy

    1. protected void Button1_Click(object sender, EventArgs e)  
    2. {  
    3.     Label1.Text = "";  
    4.     //當使用者名為1,密碼為2時,身份驗證通過  
    5.     if (TextBox1.Text == "1" && TextBox2.Text == "2")  
    6.     {  
    7.         //方式一:使用預設的身份驗證票,并跳轉到初始請求的頁面或預設頁面  
    8.         FormsAuthentication.RedirectFromLoginPage("yundao", false);  
    9.     }  
    10.     else  
    11.     {  
    12.         Label1.Text = "使用者名為1,密碼為2,請重新輸入";  
    13.     }  
    14. }  
        在以上代碼中,為了友善起見,隻要使用者輸入的使用者名為1,密碼為2,則認為身份驗證通過。身份驗證之後,接下來的三個動作應該是:
    1. 建立身份驗證票;
    2. 将身份驗證票放在Cookie中;
    3. 跳轉到登入前的網頁或預設網頁。
        在asp.net中,使用FormsAuthentication類來操作Forms身份驗證,該類中有一個RedirectFromLoginPage()方法,該方法可以一次性完成以上三個步驟:
    1. 建立一個預設的身份驗證票。
    2. 将該預設的身份驗證票存放在預設的Cookie中。此時,用于存放身份驗證票的Cookie名由web.config檔案中的<forms>節點的name屬性值決定,如果沒有設定該屬性,預設情況下,Cookie名為“.ASPXAUTH”。
    3. 跳轉網頁。跳轉網頁的位址由登入頁面的URL中的ReturnUrl參數決定,如上圖所示,登入後将跳轉到default.aspx頁面。如果登入頁面的URL中沒有ReturnUrl參數(也就是說,直接通路的登入頁面),那麼将會跳轉到web.config檔案中的<forms>節點的defaultUrl屬性值所指定的頁面,如果沒有設定該屬性,預設情況下為default.aspx頁面。

        RedirectFromLoginPage()方法中第一個參數為經過身份驗證的使用者名,這個使用者名可以與使用者的登入名相同,也可以不相同。第二個參數為是否建立永久的Cookie。通常為了安全起見,都不會建立永久的Cookie,是以該參數值通常為false。但如果建立的非永久的Cookie,那麼在關閉浏覽器視窗之後,再進入網站,就需要重新進行身份驗證,而建立永久的Cookie,隻要身份驗證過之後,無論再打開該網站中的什麼網頁,都不會要求再一次登入。

        本例源代碼可以在http://www.aspxfans.com/myBlogFile/窗體身份驗證:使用RedirectFromLoginPage方法驗證身份.rar或http://download.csdn.net/source/1962420中下載下傳。

        以上方式是最簡單的窗體身份驗證方式,因為使用的是預設的身份驗證票,但以上代碼有一個缺點,就是身份驗證通過後,要麼跳轉到登入頁面前的網頁,要麼跳轉到預設網頁。如果想停留在目前網頁,RedirectFromLoginPage()方法就無能為力了,在這種情況下,可以使用FormsAuthentication類的SetAuthCookie()方法,該方法的作用隻是建立一個預設的身份驗證票并将其寫入Cookie中,但不跳轉網頁。如果要跳轉網頁的話,可以判斷ReturnUrl參數值是否為空,再決定是否跳轉網頁。如以下代碼所示:

    [c-sharp]  view plain copy

    1. protected void Button1_Click(object sender, EventArgs e)  
    2. {  
    3.     Label1.Text = "";  
    4.     //當使用者名為1,密碼為2時,身份驗證通過  
    5.     if (TextBox1.Text == "1" && TextBox2.Text == "2")  
    6.     {  
    7.         //方式二:使用預設的身份驗證票,并寫入Cookie  
    8.         FormsAuthentication.SetAuthCookie("yundao", false);  
    9.         //判斷初始請求頁是否為空  
    10.         if (string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))  
    11.         {  
    12.             Label1.Text = "登入成功,請選擇以下網頁:";  
    13.         }  
    14.         else  
    15.         {  
    16.             Response.Redirect(Request.QueryString["ReturnUrl"].Trim());  
    17.         }  
    18.     }  
    19.     else  
    20.     {  
    21.         Label1.Text = "使用者名為1,密碼為2,請重新輸入";  
    22.     }  
    23. }  

        從以上代碼可以看出,SetAuthCookie()方法與RedirectFromLoginPage()方法相比,缺少了跳轉的步驟。是以,可以更加靈活地掌握使用者跳轉的頁面。SetAuthCookie()方法的第一個參數也是經過身份驗證的使用者名,第二個參數也是是否建立永久的Cookie

        本例的源代碼可以在http://www.aspxfans.com/myBlogFile/窗體身份驗證:使用SetAuthCookie方法驗證身份.rar 或 http://download.csdn.net/source/1962893下載下傳。

        事實上,FormsAuthentication類還有一個GetRedirectUrl()方法,該方法可以傳回初始請求頁或預設頁面,使用該方法也可以跳轉頁面。如以下代碼所示:

    [c-sharp]  view plain copy

    1. protected void Button1_Click(object sender, EventArgs e)  
    2. {  
    3.     Label1.Text = "";  
    4.     //當使用者名為1,密碼為2時,身份驗證通過  
    5.     if (TextBox1.Text == "1" && TextBox2.Text == "2")  
    6.     {  
    7.         //方式三:使用預設的身份驗證票,并寫入Cookie  
    8.         FormsAuthentication.SetAuthCookie("yundao", false);  
    9.         //跳轉到初始請求頁或預設頁面  
    10.         Response.Redirect(FormsAuthentication.GetRedirectUrl("yundao",false));  
    11.     }  
    12.     else  
    13.     {  
    14.         Label1.Text = "使用者名為1,密碼為2,請重新輸入";  
    15.     }  
    16. }  

        GetRedirectUrl()方法的第一個參數為經過身份驗證的使用者名,但第二個參數是可以忽略的參數,通常設為false。以上代碼與FormsAuthentication.RedirectFromLoginPage("yundao", false)是等價的。

        本例的源代碼可以在http://www.aspxfans.com/myBlogFile/窗體身份驗證:使用GetRedirectUrl方法跳轉網頁.rar 或 http://download.csdn.net/source/1962898下載下傳。

        前面介紹了三種窗體身份驗證的方法,這三種方法中都使用了預設的身份驗證票,而預設的身份驗證票中隻能傳遞經過驗證的使用者名,而不能傳遞其他資料。如果一個網站中,對不同的身份的使用者給予不同的權限,那麼以上三種方法都不适用了。由于要傳遞其他資料,是以必須要使用自定義的身份驗證票,如以下代碼所示:

    [c-sharp]  view plain copy

    1. protected void Button1_Click(object sender, EventArgs e)  
    2. {  
    3.     Label1.Text = "";  
    4.     //當使用者名為1,密碼為2時,身份驗證通過  
    5.     if (TextBox1.Text == "1" && TextBox2.Text == "2")  
    6.     {  
    7.         //方式四:建立自定義身份驗證票  
    8.         FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "yundao", DateTime.Now, DateTime.Now.AddMinutes(30), false, "admin");  
    9.         //将身份驗證票加密  
    10.         string EncrTicket = FormsAuthentication.Encrypt(ticket);  
    11.         //建立一個Cookie  
    12.         HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName, EncrTicket);  
    13.         //将Cookie寫入用戶端  
    14.         Response.Cookies.Add(myCookie);  
    15.         //跳轉到初始請求頁或預設頁面  
    16.         Response.Redirect(FormsAuthentication.GetRedirectUrl("yundao",false));  
    17.     }  
    18.     else  
    19.     {  
    20.         Label1.Text = "使用者名為1,密碼為2,請重新輸入";  
    21.     }  
    22. }  

        在以上代碼中,首先,使用new FormsAuthenticationTicket()語句建立了一個身份驗證票,FormsAuthenticationTicket()的第一個參數為身份驗證票的版本号,通常為1;第二個參數為經過驗證的使用者名;第三個參數為票證發出時的本地時間;第四個參數為票證過期時的本地時間;第五個參數為是否建立永久的Cookie;第六個參數,也就是最重要的參數,為要傳遞的使用者資料。如果不需要傳遞使用者資料,可以設為null。但本人建議使用空字元串,否則為票證加密時可能會産生意想不到的問題。

        建立完身份驗證票之後,可以使用FormsAuthentication類的Encrypt()方法為身份驗證票加密,加密後傳回一個字元串。

        然後建立一個Cookie,FormsAuthentication.FormsCookieName屬性可以傳回存放身份驗證票的Cookie名,也就是web.config中<Forms>小節的name屬性值。當然,在這裡還可以設定一些Cookie相關的屬性,如Cookie的path、expires、domain等,這此就不多介紹了。

        最後,将Cookie寫入到用戶端。

        這樣,一個完整的身份驗證就完成了,最後還可以選擇是否跳轉頁面。

        本例的源代碼可以在http://www.aspxfans.com/myBlogFile/窗體身份驗證:使用自定義的身份驗證票.rar 或 http://download.csdn.net/source/1962904下載下傳。本例的優點是可以傳遞使用者資料,但在傳遞使用者資料時,必須要注冊,每個Cookie的大小不能超過4KB,是以傳遞使用者的資料不能太大。

        以上四個例子在vs2005中測試通過。

     在《asp.net中的窗體身份驗證(完整篇之三:使用者登入頁面) 》中介紹了如何建立一個自定義身份驗證票,如何将自定義的身份驗證票寫入Cookie中。而在自定義的身份驗證票中,可以傳遞一個使用者資料,這個使用者資料十分有用。可以用來存放使用者權限等級、使用者VIP号、使用者角色等資料,而這些資料往往可以用來控制使用者的權限範圍。下面我們來看一下怎麼樣獲得使用者資料。

        首先,修改web.config檔案,這個就不再多介紹了,不明白的朋友去檢視《asp.net中的窗體身份驗證(完整篇之一:建立asp.net的窗體身份驗證方式) 》和《asp.net中的窗體身份驗證(完整篇之附錄:web.config中相應節點詳解) 》

        其次,建立使用者登入頁面,在本例中為AdminLogin.aspx,在單擊登入按鈕後,代碼如下所示:

    [c-sharp]  view plain copy

    1. protected void Button1_Click(object sender, EventArgs e)  
    2. {  
    3.     Label1.Text = "";  
    4.     //使用者名  
    5.     string UserName = TextBox1.Text;  
    6.     //密碼  
    7.     string UserPassword = TextBox2.Text;  
    8.     //使用者角色  
    9.     string UserRole = "";  
    10.     //使用者身份驗證  
    11.     if ((UserName == "1" && UserPassword == "2") || (UserName == "3" && UserPassword == "4"))  
    12.     {  
    13.         //判斷使用者權限  
    14.         if (UserName == "1")  
    15.         {  
    16.             UserRole = "admin";  
    17.         }  
    18.         else  
    19.         {  
    20.             UserRole = "reader";  
    21.         }  
    22.         //建立一個身份驗證票  
    23.         FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "yundao", DateTime.Now, DateTime.Now.AddMinutes(30), false, UserRole);  
    24.         //将身份驗證票加密  
    25.         string EncrTicket = FormsAuthentication.Encrypt(ticket);  
    26.         //建立一個Cookie  
    27.         HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName, EncrTicket);  
    28.         //将Cookie寫入用戶端  
    29.         Response.Cookies.Add(myCookie);  
    30.         //跳轉到初始請求頁或預設頁面  
    31.         Response.Redirect(FormsAuthentication.GetRedirectUrl("yundao",false));  
    32.     }  
    33.     else  
    34.     {  
    35.         Label1.Text = "使用者名為1,密碼為2,或使用者名為3,密碼為4。請重新輸入。";  
    36.     }  
    37. }  

        在本例中,為了簡單起見,隻要使用者名為1、密碼為2,或使用者名為3、密碼為4,都認為身份驗證通過。身份驗證通過後,建立一個身份驗證票,如果使用者名為1,身份驗證票中傳遞的使用者資料為“admin”,如果使用者名為3,身份驗證中傳遞的使用者資料為“reader”。然後加密身份驗證票,寫入用戶端Cookie。

        第三,建立一個test.aspx檔案,在該檔案中獲得使用者資料,如以下代碼所示。

    [c-sharp]  view plain copy

    1. protected void Page_Load(object sender, EventArgs e)  
    2. {  
    3.     //獲得存放身份驗證票的Cookie值,這個值是經過加密的  
    4.     string EncrTicket = Request.Cookies[FormsAuthentication.FormsCookieName].Value;  
    5.     //獲得身份驗證票  
    6.     FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(EncrTicket);  
    7.     //從身份驗證票中提取經過驗證的使用者名  
    8.     string UserName = ticket.Name;  
    9.     //從身份驗證票中提取使用者資料  
    10.     string UserData = ticket.UserData;  
    11.     Label1.Text = UserName + ",您好!您的權限為:" + UserData;  
    12. }  

        在以上代碼中,先使用Request.Cookies獲得存放身份驗證票的Cookie,其中Cookie名可以通過FormsAuthentication類的FormsCookieName屬性獲得。

        由于身份驗證票是加密後存放在Cookie中的,是以在獲得Cookie值之後,必須将身份驗證票解密。FormsAuthentication類的Decrypt()方法可以将加密後的身份驗證票(也就是存放在Cookie中的字元串)解密,并傳回解密後的身份驗證票。在asp.net中使用FormsAuthenticationTicket類來代表身份驗證票。

        獲得解密後的身份驗證票後,可以通過FormsAuthenticationTicket類的Name屬性傳回經過驗證的使用者名,也可以通過UserData屬性獲得使用者資料。

    前面介紹過了如何使用Forms方式進行使用者身份驗證,然而,在大多網站中都會有一個“退出”功能,讓使用者可以通出登入。在asp.net中,退出的方式很簡單,隻要在退出頁面中加上代碼“FormsAuthentication.SignOut()”即可。

        你可以使用Response.Redirect()在退出之後将網頁跳轉到另一個網頁,也可以使用“FormsAuthentication.RedirectToLoginPage()”将網頁跳轉到登入頁面。

    在《asp.net中的窗體身份驗證(最簡單篇)》說明了如何讓通過了身份驗證的使用者通路網站,但是該方法中有一個缺點,就是通路整個網站都需要使用者身份驗證。是以,在《asp.net中的窗體身份驗證(分目錄驗證篇)》中介紹了如何讓通過了身份驗證的使用者通路特定的目錄,例如網站根目錄中的網頁是任何使用者都能通路的,而admin目錄則隻能讓通過身份驗證的使用者通路。這種方法可以解決大部分網站的身份控制,但是,對于一 些複雜的網站而言, 這種方式就有點捉袊見肘了。例如,有一個網站,我們要求根目錄中的網頁可以讓任何使用者浏覽,而admin目錄中的網頁隻有管理者才能通路、backup目錄中的網頁隻有管理者和系統備份員才能通路、user目錄中的網頁除了匿名使用者之外的所有使用者都能通路,對于這種情況,那要怎麼辦呢?是不是還可以使用Forms身份驗證呢?

        答案是肯定的,使用Forms身份驗證可以通過角色的方式來達到上述目的。在本例中,我們可以先設定三種角色:admin、backup和reader,其中,admin角色也就是管理者角色,該角色可以通路admin目錄、backup目錄和user目錄;backup角色也就是系統備份員角色,該角色不能通路admin目錄,但可以通路backup目錄和user目錄;而reader角色是普通使用者角色,該 角色不能通路admin目錄、backup目錄,隻能通路user目錄。

        第一步、設定Forms身份驗證方式和登入網頁。

        要達到上述目的,首先我們需要修改web.config檔案,這次修改的目的是讓網站擁有Forms身份驗證功能(詳見《asp.net中的窗體身份驗證(最簡單篇)》、《asp.net中的窗體身份驗證(分目錄驗證篇)》和《asp.net中的窗體身份驗證(完整篇之附錄:web.config中相應節點詳解)》),修改方式是:在<system.web>和</system.web>中找到<authentication>節,将其改為“<authentication mode="Forms"></authentication>”,其中Forms代表使用表單認證。

        當然,你也可以在web.config檔案中設定使用者登入的網頁,設定方法為:在<authentication mode="Forms">和</authentication>節點中添加“<forms loginUrl="~/login.aspx"></forms>”代碼,其中loginUrl參數用于說明錄頁面,如果沒有設定該參數的話,預設的登入網頁就是網站根目錄的login.aspx網頁。完整的代碼如下所示:

    [c-sharp]  view plain copy

    1. <authentication mode="Forms"><!--驗證方式為窗體驗證-->  
    2.     <forms loginUrl="~/login.aspx"></forms><!--登入網頁為login.aspx-->  
    3. </authentication>  

        第二步、設定預設的使用者通路方式。

        在本例中,我們要求是網站根目錄中的網頁可以讓匿名使用者通路,是以,在設定完Forms身份驗證方式之後,我們還要設定預設的使用者通路方式——也就是讓所有的匿名使用者通路。設定方式是:在<system.web>和</system.web>節點中添加以下代碼:

    [c-sharp]  view plain copy

    1. <authorization>  
    2.     <allow users="?"/><!--預設為所有使用者都能通路-->  
    3. </authorization>  

        第三步、設定不同目錄的通路方式。

        在《asp.net中的窗體身份驗證(分目錄驗證篇)》中,曾經介紹過分目錄的驗證方式,這種方式是在目錄中建立一個web.config檔案,然後在web.config檔案中的<system.web>和</system.web>小節中,添加“<authorization></authorization>”節點,在該節點中設定不讓匿名使用者通路。在這裡,我們介紹另外一種設定不同目錄的通路方式,假設,我們現在要指定admin目錄不能讓匿名使用者通路,那麼,我們可以在根目錄的web.config檔案的<system.web>和</system.web>中添加以下代碼:

    [c-sharp]  view plain copy

    1. <location path="admin">  
    2.     <system.web>  
    3.         <authorization>  
    4.                 <!--拒絕所有匿名使用者通路-->  
    5.                 <deny users="?"/>  
    6.         </authorization>  
    7.     </system.web>  
    8. </location>  

        在以上代碼中,<location>節點的path參數用于說明要對哪個目錄可以通路控制,而<authorization>節點的作用同樣是用于設定具體的通路權限。在以上代碼中,<deny>節點用于說明拒絕哪些使用者通路,如果需要拒絕所有使用者通路,那麼就要使用到“<deny users="*"/>”代碼;如果需要允許所有使用者通路,那麼就需要使用“<allow users="*"/>”代碼。然而,在<deny>節點和<allow>節點中還可以設定拒絕或允許哪些角色的使用者通路,設定方法為“<deny roles="admin"/>”或“<allow roles="admin"/>”。其中,roles參數用于說明指定的拒絕或允許通路的角色名,如果存在多個角色,則用逗号進行分割。在本例中,要求admin目錄隻能讓admin角色的使用者通路、backup目錄可以讓admin角色和backup角色的使用者通路,user目錄可以讓所有能過身份驗證的使用者通路(無論是什麼角色),可以使用以下代碼進行設定:

    [c-sharp]  view plain copy

    1. <!--設定admin目錄的通路權限-->  
    2. <location path="admin">  
    3.     <system.web>  
    4.         <authorization>  
    5.             <!--允許角色為admin的使用者可以通路-->  
    6.             <allow roles="admin"/>  
    7.             <!--拒絕所有其他使用者通路-->  
    8.             <deny users="*"/>  
    9.             <!--注意以上兩句的次序不能變-->  
    10.         </authorization>  
    11.     </system.web>  
    12.  </location>  
    13. <!--設定backup目錄的通路權限-->  
    14. <location path="backup">  
    15.     <system.web>  
    16.         <authorization>  
    17.             <!--允許角色為admin和backup的使用者可以通路-->  
    18.             <allow roles="admin,backup"/>  
    19.             <!--拒絕所有其他使用者通路-->  
    20.             <deny users="*"/>  
    21.             <!--注意以上兩句的次序不能變-->  
    22.         </authorization>  
    23.     </system.web>  
    24. </location>  
    25. <!--設定user目錄的通路權限-->  
    26. <location path="user">  
    27.     <system.web>  
    28.         <authorization>  
    29.             <!--拒絕所有匿名使用者通路-->  
    30.             <deny users="?"/>  
    31.         </authorization>  
    32.     </system.web>  
    33. </location>  

        第四步、添加登入頁面。

        由于在本例中,指定了網站目錄中的login.aspx網頁為登入面頁,是以,在網站的根目錄中添加一個login.aspx檔案。然後在該檔案中添加一個文本框(用于輸入使用者名)和一個密碼框,再添加一個确定按鈕。為了友善起見,我們假設使用者名和密碼都為1時,登入使用者的角色為admin;使用者名和密碼都為2時,登入使用者的角色為backup;使用者名和密碼都為3時,登入使用者的角色為reader。登入網頁中的代碼如下所示:

    [c-sharp]  view plain copy

    1. //使用者名  
    2. string UserName = TextBox1.Text;  
    3. //密碼  
    4. string UserPassword = TextBox2.Text;  
    5. //使用者角色  
    6. string UserRole = "";  
    7. //使用者身份驗證  
    8. if ((UserName == "1" && UserPassword == "1") || (UserName == "2" && UserPassword == "2") || (UserName == "3" && UserPassword == "3"))  
    9. {  
    10.     //判斷使用者權限  
    11.     switch (UserName)  
    12.     {   
    13.         case "1":  
    14.             UserRole = "admin";  
    15.             break;  
    16.         case "2":  
    17.             UserRole = "backup";  
    18.             break;  
    19.         case "3":  
    20.             UserRole = "reader";  
    21.             break;  
    22.     }  
    23.     //建立一個身份驗證票  
    24.     FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "yundao", DateTime.Now, DateTime.Now.AddMinutes(30), false, UserRole);  
    25.     //将身份驗證票加密  
    26.     string EncrTicket = FormsAuthentication.Encrypt(ticket);  
    27.     //建立一個Cookie  
    28.     HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName, EncrTicket);  
    29.     //将Cookie寫入用戶端  
    30.     Response.Cookies.Add(myCookie);  
    31.     //跳轉到初始請求頁或預設頁面  
    32.     Response.Redirect(FormsAuthentication.GetRedirectUrl("yundao", false));  
    33. }  

        以上代碼和前面介紹過的身份驗證代碼類似,惟一不同的是将使用者角色寫在了身體驗證票的使用者資料(也就是FormsAuthenticationTicket()方法的最後一個參數)中。

        第五步、将使用者角色添加到表示使用者身份的GenericPrincipal對象中。

        經過上面的步驟,我們已經将使用者的角色存放在身份驗證票據中了,然而,此時用于表示使用者身份的GenericPrincipal對象中卻還隻是包含了使用者資訊而不包含使用者的角色資訊。在這一步驟中,我們必須将使用者角色資訊存放到GenericPrincipal對象中。至于怎麼樣将使用者角色資訊存放到GenericPrincipal對象中呢,我們就必須要先了解一下使用者驗證與授權的過程了:

        1、用戶端浏覽器發送一個請求到伺服器端。

        2、伺服器端接收到請求之後,會先檢查該請求中是否包含有可能存在的惡意标記,如果存在惡意标記則會傳回錯誤資訊。

        3、激活作為HTTP執行管線鍊中的第一個事件——BeginRequest事件。

        4、處理完BeginRequest事件之後,asp.net将會建立使用者辨別,此時激發AuthenticateRequest事件,該事件可以確定事件處理程式之前對請求進行身份驗證。

        5、在AuthenticateRequest 事件之後,會繼續觸發PostAuthenticateRequest 事件,該事件同時是在asp.net建立使用者辨別時觸發,但在該事件中可以通路由AuthenticateRequest事件中處理的任何資料。

        6、然後,asp.net會進入使用者授權驗證,此時會激發AuthorizeRequest事件。

        7、驗證授權完畢之後,當使用者獲得了授權時,将會激發PostAuthorizeRequest事件。

        8、到第7步為止,整個使用者身份驗證就已經完畢了,接下來将會激發PostResolveRequestCache事件,在該事件之後還會有N個事件,直到向用戶端傳回資訊為止。但那件事件都不是本文的重點,也就不詳細介紹了。

        在使用者登入确認身份之後,通常都會将身份驗證票寫到用戶端的cookie中,然後用戶端會将資訊發送到伺服器上,而在伺服器端,asp.net會為每一個HTTP請求都配置設定一個HttpApplication對象,該對象的作用是處理HTTP請求的,也就是用來處理以上步驟的。從以上步驟中可以看出,身份驗證是從AuthenticateRequest事件激發開始的,在該事件觸發後,asp.net就會根據用戶端發來的包含身份驗證票的Cookie建立使用者身份。

        而asp.net建立的使用者身份包含在HttpContext.User屬性中,可以使用“HttpContext.Current.User”來獲得得這個使用者身份。對于Forms驗證而言,HttpContext.User屬性是一個GenericPrincipal對象,該對象有兩個重要的屬性:第一個是Identity屬性,該屬性存放的是目前使用者的辨別。Identity屬性就是一個FormsIdentity對象,該對象的Name屬性可以使用者辨別、Ticket屬性可以獲得使用者的身份驗證票。另外,GenericPrincipal對象還有一個m_role屬性,這個屬性是GenericPrincipal對象的私有屬性,是以不能通過GenericPrincipal.m_role來通路,該屬性是一個數組,用于存放使用者角色。如果想知道使用者是否屬于某個角色,可以通過GenericPrincipal 對象的IsInRole()方法來判斷。然而,由于身份驗證票中并沒有提供m_role參數,是以,在asp.net建立使用者身份時,使用者是沒有角色資訊的。換句話而言,對于Forms身份驗證而言,在預設情況下,GenericPrincipal對象的m_role屬性為空。

        是以,如果想要使用角色的使用者身份驗證方式,就必須要在代表使用者身份GenericPrincipal對象中添加使用者角色。而且,這個工作必須要在第3個步驟中完成,因為第4個步驟的作用就是建立使用者辨別。是以,我們必須要在網站的根目錄中建立一個Global.asax檔案,Global.asax檔案的作用就不用我再多說了了吧?

        在Global.asax檔案中添加代碼“protected void Application_AuthenticateRequest(object sender, EventArgs e)”用于處理AuthenticateRequest事件。處理步驟如下所示:

        1、首先判斷使用者的身份驗證資訊是否為空,如果HTTP請求中就沒有使用者身份驗證資訊,那麼後面的步驟也就沒必須進行了。前面介紹過,asp.net建立的使用者身份包含在HttpContext.User屬性中,是以,在該步驟中隻需要判斷HttpContext.User屬性是否為空即可達到目的。

        2、然後判斷使用者是否已經通過了身份驗證,如果沒有通過身份驗證,那麼在通路受限網頁時,asp.net會自動跳轉到登入網頁上。前面介紹過,HttpContext.User屬性也就是一個GenericPrincipal對象,該對象的Identity屬性值為使用者辨別,那麼隻要判斷Identity.IsAuthenticated是否為true,就可以知道使用者是否已經通過身份驗證。

        3、由于asp.net的身份驗證方式有多種,是以,在這裡我們還要判斷一下使用者通過的身份驗證方式是否為Forms驗證方式。要達到該目的,隻需要判斷User.Identity是否為FormsIdentity對象即可。

        4、然後,可以獲得已經通過了Forms身份驗證的使用者辨別,再從該使用者辨別的身份驗證票中獲得使用者資料(也就是包含了使用者角色的字元串)。

        5、再然後,将使用者角色字元串放到一個角色數組中——如果一個使用者屬于多個角色,通常我們都會将不同的角色使用逗号進行分割後放在使用者資料中,然後将第4步驟中獲得的使用者資料分割後放在一個數組中,這樣就得到了一個角色數組。

        6、最後,建立一個新的GenericPrincipal對象,在建立該對象時将從第4步驟中獲得的使用者辨別以及第5步驟中獲得的角色數組一起放入GenericPrincipal對象,然後将該對象指派給HttpContext.User。

        這樣,使用者身份中就包含了角色資訊。在随後的通路用,asp.net就會自動驗證使用者的角色以判斷該使用者是否可以通路限制的目錄了。具體代碼如下所示:

    [c-sharp]  view plain copy

    1. protected void Application_AuthenticateRequest(object sender, EventArgs e)  
    2. {  
    3.     //判斷正在請求頁的使用者的身份驗證資訊是否為空  
    4.     if (HttpContext.Current.User != null)  
    5.     {  
    6.         //判斷使用者是否已經進行了身份驗證  
    7.         if (HttpContext.Current.User.Identity.IsAuthenticated)  
    8.         {  
    9.             //判斷目前使用者身份驗證的方式是否為Forms身份驗證方式  
    10.             if (HttpContext.Current.User.Identity is FormsIdentity)  
    11.             {  
    12.                 //獲得進行了Forms身份驗證的使用者辨別  
    13.                 FormsIdentity UserIdent = (FormsIdentity)(HttpContext.Current.User.Identity);  
    14.                 //從身份驗證票中獲得使用者資料  
    15.                 string UserData = UserIdent.Ticket.UserData;  
    16.                 //分割使用者資料得到使用者角色數組  
    17.                 string[] rolues = UserData.Split(',');  
    18.                 //從使用者辨別和角色組初始化GenericPrincipal類  
    19.                 HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(UserIdent, rolues);  
    20.             }  
    21.         }  
    22.     }  
    23. }  

        至此,一個完整的帶角色控制的窗體身份驗證就已經做完了。

    在前面的幾篇文章中介紹了asp.net的窗體身份驗證,這種身份驗證方式可以讓通過驗證的使用者通路指定的目錄,而沒有通過驗證的使用者不能通路該目錄下的網頁。

        但是,有一種例外,就是目錄中的html檔案例外。例如,在《asp.net中的窗體身份驗證(最簡單篇)》中介紹的,除了登入網頁之外,所有網頁都必須在登入之後才能通路,但如果在網站中添加一個HTMLPage.htm檔案,通路該檔案是不需要身份驗證的。如下圖所示:

    ASP.NET Forms驗證詳解
    ASP.NET Forms驗證詳解

        之是以出現這種情況,是由IIS的通路機制決定的。當用戶端浏覽器向Web伺服器發送請求時,Web伺服器會對所請求的檔案的擴充名進行檢查,然後決定由哪個ISAPI擴充處理這個請求,然後将請求傳遞給該ISAPI擴充。而asp.net事實上也就是一個ISAPI擴充,對于asp1.1而言,這個擴充檔案為:C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/aspnet_isapi.dll,對于asp2.0而言,這個擴充檔案為:c:/windows/microsoft.net/framework/v2.0.50727/aspnet_isapi.dll。

        很不幸的是:asp.net映身的擴充名有.aspx、.ascx、.ashx、.asmx,就是沒有.htm和.html。是以,如果受限目錄中包括.htm和.html網頁時,asp.net是不會對其進行處理的。隻要使用者可以通過IIS的權限控制,就可以通路這些檔案。

        找到原因就好辦了,如果想要讓.htm檔案和.html檔案也受asp.net控制,那麼,就必須添加映射。添加方法如下所示:

        1、在IIS中找到網站或虛拟目錄,右擊,選擇屬性,打開如下圖所示視窗。

    ASP.NET Forms驗證詳解
        2、單擊“配置”按鈕,彈出下圖視窗。
    ASP.NET Forms驗證詳解
        3、單擊“添加”按鈕,打開如下視窗。
    ASP.NET Forms驗證詳解

        4、在可執行檔案中輸入“C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/aspnet_isapi.dll”(asp.net1.1)或“c:/windows/microsoft.net/framework/v2.0.50727/aspnet_isapi.dll”(asp.net 2.0),在擴充名中輸入“htm”或“html”,注意前面不用加“.”。然後點确定。

        5、重新開機一下IIS,再通路剛才的html檔案,如下圖所示,現在要求登入了,而且在URL中也可以看到ReturnUrl參數值為htm檔案。

    ASP.NET Forms驗證詳解

    原本是沒打算寫下這一篇的,因為覺得身份驗證到了登出之後,就算完成了。可是後來有博友提出疑問,登出之後,點選浏覽器上的後退按鈕,還是可以退回到登出前頁面,起不到身份驗證的作用。

        事實上,就算使用後退按鈕回到原來的頁面,也隻能看看頁面内容,而不能對網頁進行操作。一但進行操作的話,還是會需要重新登入的。

        也許,有些朋友對頁面的安全性要求比較高,連看都不想讓人家看到。那這要怎麼辦?

        這要從浏覽器的緩存說起了。在N久以前,網絡的寬帶慢的是很慢很慢,是以,浏覽器都有一個叫做“緩存”的功能。當你浏覽了網頁之後,就會把這個網頁先緩存到本地計算機中,等你下一次再通路該網頁時,浏覽器會将緩存到本機計算機中的内容與伺服器上的内容進行比較,如果沒有更新,就不從伺服器上讀取網頁,而是直接顯示本地計算機中緩存的内容。這樣做有兩個好處,第一、用戶端可以快速打開網頁,節省等待的時間;第二、減少伺服器壓力。

        是以,這個功能就一直保留了下來,直到今天、明天或者後天。

        如果想不讓浏覽器緩存網頁,最簡單的方法就是使用HTML代碼來實作,如以下代碼所示。

    [xhtml]  view plain copy

    1. <meta http-equiv="Cache-Control" content="no-cache" />  
    2. <meta http-equiv="Pragma" content="no-cache" />  
    3. <meta http-equiv="Expires" content="-1" />  

        以上代碼應該放在<head>和</head>之間,第一句是HTTP 1.1标準中支援的,讓浏覽器不緩存網頁内容;第二句是HTTP 1.0标準中支援的,讓浏覽器不緩存網頁内容。因為不知道使用者浏覽器支援什麼标準,是以可以把兩句都加上。第三句,指定是網頁過期時間,一般來說content值都是指定的一個時間,在這個時間之前,浏覽器會顯示緩存中的内容,這個時間之後,才會從伺服器中讀取新内容。如果為0或負數,那麼就說明浏覽器永遠都從伺服器中讀取網頁内容。

        根據我十年前寫HTML的經驗,這樣寫就完全沒有問題了。可是沒想到的是……測試結果讓我大跌眼鏡、IE8、chrome6、Opera10和FireFox3.5下的測試全部沒通過,點選浏覽器的後退,還是可以看到登出後的網頁。

        還好,我還有九年前編寫ASP的經驗,于是,在.CS檔案中加入了以下代碼:

    [c-sharp]  view plain copy

    1. //禁止用戶端緩存伺服器上的網頁  
    2. Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);  
    3. //添加HTTP頭  
    4. //HTTP 1.0标準,作用相當于<meta http-equiv="Pragma" content="no-cache" />  
    5. Response.AddHeader("pragma", "no-cache");  
    6. //HTTP 1.1标準,作用相當于<meta http-equiv="Cache-Control" content="no-cache" />  
    7. Response.AddHeader("Cache-Control", "no-cache");  
    8. //設定不緩存  
    9. Response.CacheControl = "no-cache";  
    10. //設定在浏覽器上緩存的頁面的過期時間  
    11. Response.Expires = -1;  
    12. //從緩存中移除的日期  
    13. Response.ExpiresAbsolute = DateTime.Now.AddSeconds(-1);  

        曾經,在ASP中使用了類似于以上代碼的代碼,那真是天下無敵,無論是IE浏覽器還是Netscape浏覽器(多讓人懷念的浏覽器啊),都能完美地實作不能後退的功能。

        美滋滋地進行了測試,這回,又讓我跌了一次眼鏡居然除了IE8(我沒安裝别的版本的IE)能實作不能後退的功能之外,chrome6、Opera10和FireFox3.5下的測試全部沒通過。

        最後,我不得不使用asp.net的絕招了,在CS中加上以下代碼:

    [c-sharp]  view plain copy

    1. Response.Cache.SetNoStore();  

        這回的測試結果還算滿意,IE8、chrome6和FireFox3.5都通過測試,隻有Opera10還是很頑強地從緩沖中讀取網頁内容。至于怎麼讓Opera浏覽器也實作網頁過期,目前我還沒有找到方法。如果有哪位朋友知道的話,請告訴我,謝謝。

        在做測試時,以上代碼寫在子目錄的測試頁裡,測試方法為:先進入登入頁面-->登入後進入測試頁面-->進入登出頁面-->單擊浏覽器的後退按鈕回退到測試頁面。

        如果想在登出之後,使用後退按鈕不能回退到任何一頁,那麼就可以在任何一個網頁中加入以上代碼。當然,還有一個簡單的方法,在Global.asax檔案中加入以下代碼:

    [c-sharp]  view plain copy

    1. protected void Application_BeginRequest(Object sender, EventArgs e)  
    2. {  
    3.     HttpContext.Current.Response.Cache.SetNoStore();  
    4. }  
        最後,再建議一下,對于單個檔案而言,最好在aspx檔案中加上<meta>、在CS檔案中将以上代碼都加上,鬼才知道使用者浏覽器支援什麼啊。還是甯多勿少吧。

http://m.blog.csdn.net/blog/smallfools_11109/4221118