一直想知道ASP.Net是如何進行身份驗證的,今天花了點時間瞭解了一下Forms驗證。現在只是走馬觀花。


1、概述

    Asp.net的身份驗證有有三種,分別是"Windows   |   Forms   |  Passport",


Windows



將 Windows 驗證指定為默認的身份驗證模式。將它與以下任意形式的 Microsoft Internet 資訊服務 (IIS) 身份驗證結合起來使用:基本、摘要、集成 Windows 身份驗證 (NTLM/Kerberos) 或證書。在這種情況下,您的應用程式將身份驗證責任委託給基礎 IIS。



Forms



將 ASP.NET 基於表單的身份驗證指定為默認身份驗證模式。



Passport



將 Microsoft Passport Network 身份驗證指定為默認身份驗證模式。


其中又以Forms驗證用的最多。


Forms身份驗證使用用戶登錄到站點時創建的身份驗證票,然後在整個站點內跟蹤該用戶。表單身份驗證票通常包含在一個 Cookie 中。然而,ASP.NET2.0 版支援無 Cookie 表單身份驗證,結果是將票證傳入查詢字串中。

    如果用戶請求一個需要經過身份驗證的訪問的頁,且該用戶以前沒有登錄過該站點,則該用戶重定向到一個配置好的登錄頁。該登錄頁提示用戶提供憑據(通常是用戶名和密碼)。然後,將這些憑據傳遞給伺服器並針對用戶存儲(如 SQL Server 資料庫)進行驗證。在 ASP.NET 2.0 中,用戶存儲訪問可由成員身份提供程式處理。對用戶的憑據進行身份驗證後,用戶重定向到原來請求的頁面。


      如果我們在登陸Main.aspx之前,經LogIn.aspx進行認證。認證後,再次登陸Main.aspx時就不用再次登陸。如何做呢?

2、要實現這樣的功能,即實現Forms驗證的步驟如下:

  2.1、Web.config中配置ASP.NET 身份驗證方案。(如果程式中沒Web.config可以手工添加)

        如源碼:


<!--authentication:配置 ASP.NET 身份验证方案,该方案用于识别查看 ASP.NET 应用程序的用户。-->

<authentication mode="Forms" >

      <forms loginUrl="LogIn.aspx"

             protection="All"

             timeout="30"

             name =".ASPXAUTH"

             path="/"

             requireSSL="false"

             slidingExpiration="true"

             defaultUrl="Main.aspx"

             cookieless="UseDeviceProfile"

             enableCrossAppRedirects="false"

        >

      </forms>

    </authentication>




  2.2、Web.config中配置Web 應用程式的授權

        如代碼:



 <!--配置 Web 應用程式的授權,以控制用戶端對 URL 資源的訪問。-->

    <authorization>

      <deny users="?"></deny>

    </authorization>




  2.3、身份驗證的資訊存入Cookie中

        在登陸頁面“LogIn.aspx”中“登陸”按鈕事件中增加以下代碼:


        /// <summary>

        /// 登陸按鈕事件的方法

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        void btnCommit_Click(object sender, EventArgs e)

        {


            //得到輸入的用戶名

            string sUser = txtUser.Text.ToString();

            //得到輸入的密碼

            string sPassowrd = txbPassword.Text.ToString();

            if (sUser == "scott" && sPassowrd == "123")

            {

                //创建一个身份票据,用於保存用户信息

                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, sUser, DateTime.Now, DateTime.Now.AddMinutes(1),

                         false, string.Empty, FormsAuthentication.FormsCookiePath);

                //加密

                string encrytedTicket = FormsAuthentication.Encrypt(ticket);

                //建立Cookie

                HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrytedTicket);

                //設置可以不通过 HTTPS传输 Cookie

                authCookie.Secure = false;

                //设置Cookie 的过期日期和时间。

                authCookie.Expires = ticket.Expiration;

                //存入Cookie

                Response.Cookies.Add(authCookie);


                //将用户重定向到最初请求页面。

                Response.Redirect(FormsAuthentication.GetRedirectUrl(sUser, false));


            }

        }




  2.4、讀取保存在電腦中的Cookie。

        可以使用Global.asax。此檔可以自己添加。我們可以用Application_AuthenticateRequest事件,對存入的Cookie並進行解密。


        /// <summary>

        /// 当安全模块已建立用户标识时发生的事件方法 

        /// 主要是对用户的身份票证进行解密,而后将其加入到用户的http上下文中

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        protected void Application_AuthenticateRequest(object sender, EventArgs e)

        {

            //获取用于存储 Forms 身份验证票证的 Cookie 名称。 

            string cookieName = FormsAuthentication.FormsCookieName;


            //讀取客戶端Cookie

            HttpCookie authCookie = Context.Request.Cookies[cookieName];

            if (authCookie == null)

            {

                return;

            }

            FormsAuthenticationTicket authTicket = null;

            //获取验证票据。

            authTicket = FormsAuthentication.Decrypt(authCookie.Value);

            if (authTicket == null)

            {

                return;

            }

            //取得一个存储在票证中的用户特定的字符串。 

            string[] roles = authTicket.UserData.Split(new char[] { ',' });

            //建立一个使用 Forms 身份验证进行了身份验证的用户标识

            FormsIdentity id = new FormsIdentity(authTicket);

            //从用户标识和角色名称数组(标识表示的用户属于该数组)初始化 GenericPrincipal 类的新实例。

            GenericPrincipal principal = new GenericPrincipal(id, roles);

            //把生成的验证票信息和角色信息赋给当前用户

            Context.User = principal;

        }


3、 授權的詳細過程:     

    3.1   一旦一個用戶訪問這個網站,就行登錄確認了身份,身份驗證票的cookie也寫到了用戶端。之後,這個用戶再次申請這個web的頁面,身份驗證票的 cookie就會發送到服務端。在服務端,asp.net為每一個http請求都分配一個HttpApplication物件來處理這個請求,在 HttpApplication.AuthenticateRequest事件後,安全模組已建立用戶標識,就是此用戶的身份在web端已經建立起來,這個身份完全是由用戶端發送回來的身份驗證票的cookie建立的。  

    3.2  用戶身份在HttpContext.User   屬性中,在頁面中可以通過Page.Context   來獲取同這個頁面相關的HttpContext物件。對於Forms驗證,HttpContext.User屬性是一個GenericPrincipal 類型的物件,GenericPrincipal只有一個公開的屬性Identity,有個私有的m_role屬性,是string[]類型,存放此用戶是屬於哪些role的陣列,還有一個公開的方法IsInRole(string   role),來判斷此用戶是否屬於某個角色。  

  由於身份驗證票的cookie中根本沒有提供role這個屬性,就是說Forms身份驗證票沒有提供此用戶的role資訊,所以,對於Forms驗證,在服務端得到的GenericPrincipal   用戶物件的m_role屬性永遠是空的。  

    3.3   GenericPrincipal.   Identity   屬性是一個FormsIdentity類型的物件,這個物件有個Name屬性,就是此用戶的標示,訪問授權就是將此屬性做為user來進行授權驗證的。 FormsIdentity還有一個屬性,就是Ticket屬性,此屬性是身份驗證票FormsAuthenticationTicket類型,就是之前伺服器寫到用戶端的身份驗證票。  

  伺服器在獲取到身份驗證票FormsAuthenticationTicket物件後,查看這個身份驗證票是不是非持久的身份驗證,是的話要根據 web.config中timeout屬性設置的有效期來更新這個身份驗證票的cookie(為避免危及性能,在經過了超過一半的指定時間後更新該   Cookie。這可能導致精確性上的損失。持久性   Cookie   不超時。)  

  3.4   在HttpApplication.ResolveRequestCache事件之前,asp.net開始取得用戶請求的頁面,建立 HttpHandler控制點。這就意味著,在HttpApplication.ResolveRequestCache事件要對用戶訪問許可權就行驗證,看此用戶或角色是否有許可權訪問這個頁面,之後在這個請求的生命週期內再改變此用戶的身份或角色就沒有意義了。  

   

  以上是Forms驗證的全過程,可以看出,這個Forms驗證是基於用戶的,沒有為角色的驗證提供直接支援。身份驗證票 FormsAuthenticationTicket   中的Name屬性是用戶標示,其實還有一個屬性UserData,這個屬性可以由應用程式來寫入自定義的一些資料,我們可以利用這個欄位來存放role的資訊,從而達到基於角色驗證的目的。


4、 代碼內容說明:

  2.6.1<authentication>元素的屬性說明:



 2.6.2 <authentication>的 forms 項目的屬性說明:


  2.6.3 Authorization元素的子元素說明


子標記



說明



allow



向授權規則映射添加一個規則,該規則允許對資源進行訪問。



deny



向授權規則映射添加一條拒絕對資源的訪問的授權規則。


  2.6.4 Authorization的Deny元素的屬性說明:


屬性



說明



users



一個逗號分隔的用戶名列表,這些用戶名被拒絕對資源進行訪問。問號 (?) 表示拒絕匿名用戶;星號 (*) 表示拒絕所有用戶帳戶訪問。必選的 String 屬性。



roles



一個逗號分隔的角色列表,這些角色被拒絕對資源進行訪問。必選的 String 屬性。



verbs



一個逗號分隔的 HTTP 傳輸方法列表,這些 HTTP 傳輸方法被授予對資源的訪問許可權。可選的 String 屬性。
註冊到 ASP.NET 的謂詞為 GET、HEAD、POST 和 DEBUG。