<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">
<asp:Label id="lblMsg" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat="server" />
using System.Data.SqlClient;
using System.Web.Security;
private bool ValidateUser(string userName, string passWord) {
// 輸入驗證
if (string.IsNullOrEmpty(userName) || userName.Length > 15) return false;
if (string.IsNullOrEmpty(passWord) || passWord.Length > 25) return false;
string lookupPassword = null;
try {
using (var conn = new SqlConnection("server=localhost;Integrated Security=SSPI;database=pubs")) {
conn.Open();
using (var cmd = new SqlCommand("SELECT Pwd FROM Users WHERE uname = @userName", conn)) {
cmd.Parameters.Add("@userName", SqlDbType.VarChar, 25).Value = userName;
lookupPassword = (string)cmd.ExecuteScalar();
}
}
} catch (Exception ex) {
System.Diagnostics.Trace.WriteLine($"[ValidateUser] Exception: {ex.Message}");
return false;
}
if (lookupPassword == null) return false;
// 區分大小寫比對
return string.Compare(lookupPassword, passWord, false) == 0;
}
關鍵點:
using 確保連線釋放ExecuteScalar 單值查詢效能最佳false 參數)private void cmdLogin_ServerClick(object sender, EventArgs e) {
if (ValidateUser(txtUserName.Value, txtUserPass.Value)) {
FormsAuthentication.RedirectFromLoginPage(txtUserName.Value, chkPersistCookie.Checked);
} else {
Response.Redirect("Logon.aspx", true);
}
}
private void cmdLogin_ServerClick(object sender, EventArgs e) {
if (ValidateUser(txtUserName.Value, txtUserPass.Value)) {
var ticket = new FormsAuthenticationTicket(
1, txtUserName.Value, DateTime.Now,
DateTime.Now.AddMinutes(30),
chkPersistCookie.Checked,
"custom user data" // 可攜帶角色等自訂資料
);
string encTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
if (chkPersistCookie.Checked) cookie.Expires = ticket.Expiration;
cookie.Path = FormsAuthentication.FormsCookiePath;
Response.Cookies.Add(cookie);
string redirectUrl = Request["ReturnUrl"] ?? "Default.aspx";
Response.Redirect(redirectUrl, true);
} else {
Response.Redirect("Logon.aspx", true);
}
}
方式 B 優勢:可在票據 UserData 嵌入角色、權限、使用者 ID 等,避免每次請求查詢資料庫。
this.cmdLogin.ServerClick += new EventHandler(this.cmdLogin_ServerClick);
<input type="submit" Value="SignOut" runat="server" id="cmdSignOut">
using System.Web.Security;
private void cmdSignOut_ServerClick(object sender, EventArgs e) {
FormsAuthentication.SignOut(); // 清除認證 Cookie
Response.Redirect("Logon.aspx", true);
}
this.cmdSignOut.ServerClick += new EventHandler(this.cmdSignOut_ServerClick);
Default.aspx → 應導向 Logon.aspxuser1/user1 → 登入成功導向 Default.aspxFormsAuthentication.HashPasswordForStoringInConfigFile(pwd, "SHA1")(或更強演算法)<connectionStrings> + ConfigurationManager.ConnectionStrings<forms requireSSL="true" /> 強制加密傳輸protection="All"(驗證+加密),HttpOnly、Secure 標記Cache-Control: no-cache 避免認證 Cookie 被快取表單認證雖為經典機制,但在 ASP.NET Core 時代已演進為 Cookie 認證中介軟體。理解其核心原理(票據、Cookie、滑動過期、資料保護),有助於在現代架構中正確配置認證流程。