使用 C#.NET 在 ASP.NET 應用程式中實作表單型驗證

本文示範如何使用資料庫來儲存使用者,以實作窗體型驗證。 它指的是下列 Microsoft .NET Framework 類別庫命名空間:

  • System.Data.SqlClient
  • System.Web.Security

原始產品版本: ASP.NET
原始 KB 編號: 301240

需求

下列清單概述您需要的建議硬體、軟體、網路基礎結構和 Service Pack:

  • Visual Studio .NET
  • Internet Information Services (IIS) 5.0 版或更新版本
  • SQL Server

使用 C# .NET 建立 ASP.NET 應用程式

  1. 開啟 Visual Studio .NET。
  2. 建立新的 ASP.NET Web 應用程式,並指定名稱和位置。

在 Web.config 檔案中設定安全性設定

本節示範如何新增和修改 <authentication><authorization> 組態區段,以設定 ASP.NET 應用程式使用表單型驗證。

  1. 在 [方案總管] 中,開啟 Web.config 檔案。

  2. 將驗證模式變更為 Forms

  3. 插入標記 <Forms> ,並填入適當的屬性。 複製下列程式代碼,然後在 [編輯] 功能選取 [貼上為 HTML],將程式代碼貼到檔案的 區段中<authentication>

    <authentication mode="Forms">
        <forms name=".ASPXFORMSDEMO" loginUrl="logon.aspx"
            protection="All" path="/" timeout="30" />
    </authentication>
    
  4. 拒絕存取區段中的匿名使用者, <authorization> 如下所示:

    <authorization>
        <deny users ="?" />
        <allow users = "*" />
    </authorization>
    

建立範例資料庫數據表以儲存使用者詳細數據

本節說明如何建立範例資料庫來儲存使用者的使用者名稱、密碼和角色。 如果您想要將使用者角色儲存在資料庫中,並實作角色型安全性,則需要角色數據行。

  1. 在 [ 開始] 功能表上,選取 [ 執行],然後輸入記事本以開啟 [記事本]。

  2. 反白顯示下列 SQL 腳本程式代碼,以滑鼠右鍵按兩下程式代碼,然後選取 [ 複製]。 在記事本中,選取 [編輯] 功能表上的 [貼上],以貼上下列程序代碼:

    if exists (select * from sysobjects where id =
    object_id(N'[dbo].[Users]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
        drop table [dbo].[Users]
    GO
    CREATE TABLE [dbo].[Users] ([uname] [varchar] (15) NOT NULL,
        [Pwd] [varchar] (25) NOT NULL,
        [userRole] [varchar] (25) NOT NULL,
    ) ON [PRIMARY]
    GO
    ALTER TABLE [dbo].[Users] WITH NOCHECK ADD
        CONSTRAINT [PK_Users] PRIMARY KEY NONCLUSTERED
        ([uname]
        ) ON [PRIMARY]
    GO
    
    INSERT INTO Users values('user1','user1','Manager')
    INSERT INTO Users values('user2','user2','Admin')
    INSERT INTO Users values('user3','user3','User')
    GO
    
  3. 將檔案儲存為 Users.sql

  4. 在 SQL Server 計算機上,在查詢分析器中開啟Users.sql。 從資料庫清單中,選取 pubs,然後執行腳本。 這項作業會建立範例用戶數據表,並在 Pubs 資料庫中填入要與此範例應用程式搭配使用的數據表。

建立Logon.aspx頁面

  1. 將新的 Web Form 新增至名為 Logon.aspx 的專案。

  2. 在編輯器中開啟 [Logon.aspx] 頁面,然後切換至 [HTML 檢視]。

  3. 複製下列程式代碼,並使用 [編輯] 功能表上的 [貼上為 HTML] 選項,在標記之間<form>插入程序代碼:

    <h3>
        <font face="Verdana">Logon Page</font>
    </h3>
    <table>
        <tr>
            <td>Email:</td>
            <td><input id="txtUserName" type="text" runat="server"></td>
            <td><ASP:RequiredFieldValidator ControlToValidate="txtUserName"
                Display="Static" ErrorMessage="*" runat="server" 
                ID="vUserName" /></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input id="txtUserPass" type="password" runat="server"></td>
            <td><ASP:RequiredFieldValidator ControlToValidate="txtUserPass"
            Display="Static" ErrorMessage="*" runat="server"
            ID="vUserPass" />
            </td>
        </tr>
        <tr>
            <td>Persistent Cookie:</td>
            <td><ASP:CheckBox id="chkPersistCookie" runat="server" autopostback="false" /></td>
            <td></td>
        </tr>
    </table>
    <input type="submit" Value="Logon" runat="server" ID="cmdLogin"><p></p>
    <asp:Label id="lblMsg" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat="server" />
    

    此 Web Form 是用來向使用者呈現登入表單,讓他們可以提供使用者名稱和密碼來登入應用程式。

  4. 切換至 [設計] 檢視,然後儲存頁面。

撰寫事件處理程式的程式代碼,使其驗證用戶認證

本節會顯示放在程式代碼後置頁面 (Logon.aspx.cs) 的程序代碼。

  1. 按兩下 [登入] 以開 啟Logon.aspx.cs 檔案。

  2. 在程式代碼後置檔案中匯入必要的命名空間:

    using System.Data.SqlClient;
    using System.Web.Security;
    
  3. 建立函式 ValidateUser ,藉由查看資料庫來驗證用戶認證。 請確定您變更 Connection 字串以指向您的資料庫。

    private bool ValidateUser( string userName, string passWord )
    {
        SqlConnection conn;
        SqlCommand cmd;
        string lookupPassword = null;
    
        // Check for invalid userName.
        // userName must not be null and must be between 1 and 15 characters.
        if ( ( null == userName ) || ( 0 == userName.Length ) || ( userName.Length > 15 ))
        {
            System.Diagnostics.Trace.WriteLine( "[ValidateUser] Input validation of userName failed." );
            return false;
        }
    
        // Check for invalid passWord.
        // passWord must not be null and must be between 1 and 25 characters.
        if ( ( null == passWord ) || ( 0 == passWord.Length ) || ( passWord.Length > 25 ))
        {
            System.Diagnostics.Trace.WriteLine( "[ValidateUser] Input validation of passWord failed." );
            return false;
        }
    
        try
        {
            // Consult with your SQL Server administrator for an appropriate connection
            // string to use to connect to your local SQL Server.
            conn = new SqlConnection( "server=localhost;Integrated Security=SSPI;database=pubs" );
            conn.Open();
    
            // Create SqlCommand to select pwd field from users table given supplied userName.
            cmd = new SqlCommand( "Select pwd from users where uname=@userName", conn );
            cmd.Parameters.Add( "@userName", SqlDbType.VarChar, 25 );
            cmd.Parameters["@userName"].Value = userName;
    
            // Execute command and fetch pwd field into lookupPassword string.
            lookupPassword = (string) cmd.ExecuteScalar();
    
            // Cleanup command and connection objects.
            cmd.Dispose();
            conn.Dispose();
        }
        catch ( Exception ex )
        {
            // Add error handling here for debugging.
            // This error message should not be sent back to the caller.
            System.Diagnostics.Trace.WriteLine( "[ValidateUser] Exception " + ex.Message );
        }
    
        // If no password found, return false.
        if ( null == lookupPassword )
        {
            // You could write failed login attempts here to event log for additional security.
            return false;
        }
    
        // Compare lookupPassword and input passWord, using a case-sensitive comparison.
        return ( 0 == string.Compare( lookupPassword, passWord, false ));
    }
    
  4. 您可以使用兩種方法之一來產生窗體驗證 Cookie,並將使用者重新導向至事件中的適當頁面 cmdLogin_ServerClick 。 這兩種案例都提供範例程序代碼。 根據您的需求使用其中一個。

    • RedirectFromLoginPage呼叫 方法以自動產生窗體驗證 Cookie,並在事件中將使用者重新導向至適當的頁面cmdLogin_ServerClick

      private void cmdLogin_ServerClick(object sender, System.EventArgs e)
      {
          if (ValidateUser(txtUserName.Value,txtUserPass.Value))
              FormsAuthentication.RedirectFromLoginPage(txtUserName.Value, chkPersistCookie.Checked);
          else
              Response.Redirect("logon.aspx", true);
      }
      
    • 產生驗證票證、加密、建立 Cookie、將它新增至回應,以及重新導向使用者。 這項作業可讓您更充分掌控如何建立 Cookie。 在這裡情況下,您也可以包含自訂資料以及 FormsAuthenticationTicket

      private void cmdLogin_ServerClick(object sender, System.EventArgs e)
      {
          if (ValidateUser(txtUserName.Value,txtUserPass.Value))
          {
              FormsAuthenticationTicket tkt;
              string cookiestr;
              HttpCookie ck;
              tkt = new FormsAuthenticationTicket(1, txtUserName.Value, DateTime.Now,
              DateTime.Now.AddMinutes(30), chkPersistCookie.Checked, "your custom data");
              cookiestr = FormsAuthentication.Encrypt(tkt);
              ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
              if (chkPersistCookie.Checked)
                  ck.Expires=tkt.Expiration;
              ck.Path = FormsAuthentication.FormsCookiePath;
              Response.Cookies.Add(ck);
      
              string strRedirect;
              strRedirect = Request["ReturnUrl"];
              if (strRedirect==null)
                  strRedirect = "default.aspx";
              Response.Redirect(strRedirect, true);
          }
          else
              Response.Redirect("logon.aspx", true);
      }
      
  5. 請確定下列程式代碼已新增至 InitializeComponent Web Form Designer 產生之程式代碼中的 方法:

    this.cmdLogin.ServerClick += new System.EventHandler(this.cmdLogin_ServerClick);
    

建立Default.aspx頁面

本節會建立測試頁面,讓使用者在驗證之後重新導向至該頁面。 如果用戶流覽至此頁面,但未先登入應用程式,則會將他們重新導向至登入頁面。

  1. 將現有的 WebForm1.aspx 頁面重新命名為 Default.aspx,並在編輯器中開啟它。

  2. 切換至 HTML 檢視,並在標記之間 <form> 複製下列程式代碼:

    <input type="submit" Value="SignOut" runat="server" id="cmdSignOut">
    

    此按鈕可用來從窗體驗證會話註銷。

  3. 切換至 [設計] 檢視,然後儲存頁面。

  4. 在程式代碼後置檔案中匯入必要的命名空間:

    using System.Web.Security;
    
  5. 按兩下 [註銷 ] 以開啟程式代碼後置頁面 (Default.aspx.cs) ,然後在事件處理程式中 cmdSignOut_ServerClick 複製下列程式代碼:

    private void cmdSignOut_ServerClick(object sender, System.EventArgs e)
    {
        FormsAuthentication.SignOut();
        Response.Redirect("logon.aspx", true);
    }
    
  6. 請確定下列程式代碼已新增至 InitializeComponent Web Form Designer 產生之程式代碼中的 方法:

    this.cmdSignOut.ServerClick += new System.EventHandler(this.cmdSignOut_ServerClick);
    
  7. 儲存並編譯專案。 您現在可以使用應用程式。

其他注意事項

  • 您可能想要將密碼安全地儲存在資料庫中。 您可以使用名為 的FormsAuthenticationHashPasswordForStoringInConfigFile類別公用程式函式來加密密碼,然後再將密碼儲存在資料庫或組態檔中。

  • 您可能想要將 SQL 連線資訊儲存在組態檔 (Web.config) ,以便在必要時輕鬆修改。

  • 您可以考慮新增程序代碼,以防止嘗試使用不同密碼組合的駭客登入。 例如,您可以包含只接受兩次或三次登入嘗試的邏輯。 如果使用者無法在某些嘗試中登入,您可能會想要在資料庫中設定旗標,以在使用者造訪不同的頁面或呼叫您的支援行來重新啟用其帳戶之前,不允許他們登入。 此外,您應該視需要新增適當的錯誤處理。

  • 因為使用者是根據驗證 Cookie 來識別,所以您可能想要在此應用程式上使用安全套接字層 (SSL) ,讓沒有人可以驗證 Cookie 和任何其他正在傳輸的重要資訊。

  • 表單型驗證需要您的用戶端在其瀏覽器上接受或啟用 Cookie。

  • 組態區段的 <authentication> timeout 參數會控制重新產生驗證 Cookie 的間隔。 您可以選擇可提供更佳效能和安全性的值。

  • 因特網上的某些中繼 Proxy 和快取可能會快取包含 Set-Cookie 標頭的 Web 伺服器回應,然後傳回給不同的使用者。 由於窗體型驗證會使用 Cookie 來驗證使用者,因此此行為可能會導致使用者從原本不適合的中繼 Proxy 或快取接收 Cookie,不小心 (或刻意) 模擬其他使用者。

參考資料