本文將告訴您,如何使用資料庫來實作表單型驗證,以便儲存使用者詳細資訊。
需求
下面清單列出了建議使用的硬體、軟體、網路基礎架構以及所需的 Service Pack:
- Microsoft Visual Studio .NET
- Microsoft Internet Information Services 5.0 (IIS)
或更新的版本
- Microsoft SQL Server
使用 C# .NET 建立 ASP.NET 應用程式
- 開啟 Visual Studio .NET。
- 建立新的 ASP.NET Web 應用程式,並指定其名稱和位置。
在 Web.config 檔案中設定安全性設定
本節將告訴您,如何加入並修改
<authentication> 和
<authorization> 設定區段來設定 ASP.NET 應用程式,使其使用表單型驗證。
- 在 [方案總管] 中開啟 Web.config 檔案。
- 將驗證模式變更成 [表單]。
- 插入 <Forms> 標籤,並填入適當屬性。(如需有關這些屬性的詳細資訊,請參閱<參考>一節中所列的 MSDN 文件或「快速入門」文件)。複製下列程式碼,再按一下
[編輯] 功能表的 [貼成 HTML],將此段程式碼貼到檔案的 <authentication> 區段中:
<authentication mode="Forms">
<forms name=".ASPXFORMSDEMO" loginUrl="logon.aspx"
protection="All" path="/" timeout="30" />
</authentication>
- 拒絕存取下列 <authorization> 區段中的匿名使用者:
<authorization>
<deny users ="?" />
<allow users = "*" />
</authorization>
建立範例資料庫資料表儲存使用者詳細資訊
本節將告訴您,如何建立範例資料庫來儲存使用者名稱、密碼和使用者的角色。如果您要在資料庫中儲存使用者角色和實作角色安全性,就需要用到角色欄位。
- 在 [開始] 功能表上按一下 [執行],再輸入
notepad 以開啟 [記事本]。
- 反白選取下列 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
- 將檔案儲存為 Users.sql。
- 從 Microsoft SQL Server 電腦的 Query Analyzer 開啟
Users.sql。再從資料庫清單中,按一下 pubs,執行這段指令碼。這樣便會在本範例應用程式會用到的 Pubs
資料庫中,建立並填入範例使用者資料表。
建立 Logon.aspx 頁面
- 在名為 Logon.aspx 的專案中加入新的網頁表單。
- 在編輯器中開啟 Logon.aspx 頁面,並切換成 HTML 檢視。
- 複製下列程式碼,並使用 [編輯] 功能表上的 [貼成
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" />
這個網頁表單是用來向使用者顯示登入表單,使其能夠提供使用者名稱和密碼以登入此應用程式。 - 切換至 [設計] 檢視,再儲存此頁面。
編寫事件處理常式程式碼以驗證使用者憑證
本節將列出置於程式碼後置網頁 (Logon.aspx.cs) 中的程式碼。
- 按兩下 [登入] 以開啟 Logon.aspx.cs 檔案。
- 將必要的命名空間匯入到程式碼後置檔案:
using System.Data.SqlClient;
using System.Web.Security;
- 建立 ValidateUser 函式,以便查詢資料庫來驗證使用者憑證 (確定您有將「連線」字串變更為指向您的資料庫)。
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 ) );
}
- 您可以使用兩種方法的其中之一來產生表單型驗證 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); }
- 確定「網頁表單設計工具」所產生程式碼中的 InitializeComponent 方法,已經加入下面這段程式碼:
this.cmdLogin.ServerClick += new System.EventHandler(this.cmdLogin_ServerClick);
建立 Default.aspx 頁面
本節會建立使用者在驗證過後,將重新導向至其中的測試頁面。如果使用者未先登入應用程式就瀏覽至這個頁面,則系統會將使用者重新導向到登入頁面。
- 將現有的 WebForm1.aspx 頁面重新命名為
Default.aspx,再於編輯器中開啟這個頁面。
- 切換成 [HTML] 檢視,再將下面程式碼複製到 <form> 標籤之間:
<input type="submit" Value="SignOut" runat="server" id="cmdSignOut">
這個按鈕是用來登出表單驗證工作階段。 - 切換至 [設計] 檢視,再儲存此頁面。
- 將必要的命名空間匯入到程式碼後置檔案:
using System.Web.Security;
- 按兩下 [SignOut] 以開啟程式碼後置網頁 (Default.aspx.cs),並將下列程式碼複製到 cmdSignOut_ServerClick 事件處理常式中:
private void cmdSignOut_ServerClick(object sender, System.EventArgs e)
{
FormsAuthentication.SignOut();
Response.Redirect("logon.aspx", true);
}
- 確定「網頁表單設計工具」所產生程式碼中的 InitializeComponent 方法,已經加入下面這段程式碼:
this.cmdSignOut.ServerClick += new System.EventHandler(this.cmdSignOut_ServerClick);
- 儲存並編譯專案。您現在可以使用這個應用程式。
其他注意事項
- 您可能會希望能在資料庫中安全地儲存密碼。您可以使用名為 HashPasswordForStoringInConfigFile 的 FormsAuthentication 類別公用程式函式先為密碼進行加密,再將密碼儲存到資料庫或設定檔中。
- 您可以將 SQL 連線資訊儲存到設定檔 (Web.config),以在必要時方便進行修改。
- 您可以考慮加入程式碼來防止駭客使用不同密碼組合登入。例如,您可以包含只接受二次或三次嘗試登入次數的邏輯。如果使用者無法在特定嘗試次數之內完成登入,您可以在資料庫中設定旗標,設定在該使用者造訪不同頁面或撥打支援電話來重新啟用其帳戶之前,皆不允許該使用者登入。此外,您應該在任何必要時機加入適當的錯誤處理。
- 由於會根據驗證 Cookie 來加以識別使用者,所以您可能想這個應用程式中使用 Secure Sockets
Layer (SSL),防止任何人欺騙驗證 Cookie 和傳送過程中的任何有價資訊。
- 表單型驗證會要求用戶端接受或是啟用瀏覽器的 Cookie 功能。
- <authentication> 設定區段的 timeout 參數會控制驗證 Cookie 的產生時間間隔。您可以選擇可提供較高效能和安全性的值。
- 某些在 Internet 上的中繼 Proxy 和快取,會快取其中包含 Set-Cookie 標題的 Web
伺服器回應,並將這些標題傳回給不同使用者。由於表單型驗證會使用 Cookie 來驗證使用者,因此如果在此時接收到從非原來指定使用的中繼 Proxy
或快取發出的 Cookie,就可能會讓使用者不小心 (或故意) 模擬其他使用者。
如需有關如何使用
<credentials> 區段來儲存使用者資料和密碼,以便實作簡易表單型驗證的詳細資訊,請參閱下列 GotDotNet ASP.NET 快速入門範例:
如需有關如何使用 XML 檔案來儲存使用者資料和密碼,以便實作表單型驗證的詳細資訊,請參閱 .NET Framework
Software Development Kit (SDK) 文件中的下列主題:
如需有關 ASP.NET Web 應用程式安全性的詳細資訊,請參閱下列《Microsoft .NET Framework
開發人員指南》文件:
如需有關
System.Web.Security 命名空間的詳細資訊,請參閱下列 Microsoft .NET Framework Reference 文件:
如需有關 ASP.NET 設定的詳細資訊,請參閱下列《Microsoft .NET Framework 開發人員指南》文件:
如需有關 ASP.NET 安全性指南的詳細資訊,請參閱下列 MSDN 白皮書:
如需有關 ASP.NET 的一般相關資訊,請造訪下列 MSDN 新聞群組: