共用方式為


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

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

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

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

需求

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

  • Visual Studio .NET
  • 網際網路資訊服務 (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 資料庫中填入要與這個範例應用程式搭配使用的數據表。

建立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 表單可用來向使用者呈現登入表單,以便他們提供使用者名稱和密碼來登入應用程式。

    如需詳細資訊,請參閱 RequiredFieldValidator 類別

  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 表單設計工具產生的程式代碼中的 方法:

    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 表單設計工具產生的程式代碼中的 方法:

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

其他注意事項

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

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

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

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

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

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

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

參考資料