萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> ASP.NET 程式設計

ASP.NET Forms Authentication 表單驗證完整實作教學

Forms Authentication 架構概覽

ASP.NET Forms Authentication 透過 **加密 Cookie** (`FormsAuthenticationTicket`) 維持使用者登入狀態。核心流程:

  1. 使用者登入 → 驗證通過
  2. `FormsAuthentication.SetAuthCookie` / `RedirectFromLoginPage` 建立加密 Ticket 寫入 Cookie
  3. 後續請求 → `FormsAuthenticationModule` 解密 Ticket → 填入 `HttpContext.User`
  4. `[Authorize]` / `web.config ` 自動攔截未驗證請求

最小完整範例 (Web Forms)

1. Web.config 設定

<configuration>
  <system.web>
    <authentication mode="Forms">
      <forms 
        loginUrl="Login.aspx" 
        name=".ASPXAUTH" 
        timeout="30" 
        path="/" 
        protection="All" 
        requireSSL="false" 
        slidingExpiration="true" />
    </authentication>
    <authorization>
      <deny users="?" /> <!-- 拒絕匿名 -->
    </authorization>
  </system.web>
</configuration>

關鍵屬性:`slidingExpiration="true"` 活動延長期限;`protection="All"` 加密+簽章;`requireSSL="true"` 生產環境必開。

2. Login.aspx (登入頁)

<%@ Page Language="C#" %>
<script runat="server">
    protected void btnLogin_Click(object sender, EventArgs e)
    {
        // 實務應查詢資料庫、驗證密碼雜湊 (BCrypt/PBKDF2)
        if (ValidateUser(txtUser.Text, txtPass.Text))
        {
            // 建立票據:使用者名稱、是否持久、逾時分鐘
            var ticket = new FormsAuthenticationTicket(
                1, txtUser.Text, DateTime.Now, DateTime.Now.AddMinutes(30), 
                chkPersist.Checked, "Admin,Editor", FormsAuthentication.FormsCookiePath);
            
            string encTicket = FormsAuthentication.Encrypt(ticket);
            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
            {
                HttpOnly = true,
                Secure = FormsAuthentication.RequireSSL,
                Path = FormsAuthentication.FormsCookiePath
            };
            if (chkPersist.Checked) cookie.Expires = ticket.Expiration;
            Response.Cookies.Add(cookie);

            // 導向原請求頁或預設頁
            Response.Redirect(FormsAuthentication.GetRedirectUrl(txtUser.Text, chkPersist.Checked));
        }
        else
        {
            lblError.Text = "帳號或密碼錯誤";
        }
    }

    private bool ValidateUser(string user, string pass)
    {
        // 示範:實際應使用參數化查詢 + 密碼雜湊驗證
        return user == "admin" && pass == "password123"; 
    }
</script>
<html><body>
<form runat="server">
    帳號: <asp:TextBox ID="txtUser" runat="server" /><br/>
    密碼: <asp:TextBox ID="txtPass" TextMode="Password" runat="server" /><br/>
    <asp:CheckBox ID="chkPersist" runat="server" Text="記住我" /><br/>
    <asp:Button ID="btnLogin" Text="登入" OnClick="btnLogin_Click" runat="server" />
    <asp:Label ID="lblError" ForeColor="Red" runat="server" />
</form></body></html>

3. Default.aspx (受保護頁面)

<%@ Page Language="C#" %>
<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        lblWelcome.Text = $"歡迎, {Context.User.Identity.Name} | 角色: {((FormsIdentity)Context.User.Identity).Ticket.UserData}";
    }
    protected void btnLogout_Click(object sender, EventArgs e)
    {
        FormsAuthentication.SignOut();
        Response.Redirect("Login.aspx");
    }
</script>
<html><body>
<asp:Label ID="lblWelcome" runat="server" /><br/>
<asp:Button ID="btnLogout" Text="登出" OnClick="btnLogout_Click" runat="server" />
</body></html>

進階主題

角色型授權 (Role-Based Authorization)


// Ticket 建立時夾帶角色字串 (逗號分隔)
var ticket = new FormsAuthenticationTicket(..., "Admin,Editor", ...);

// Global.asax 解析角色填入 Principal
protected void Application_AuthenticateRequest()
{
    if (Request.Cookies[FormsAuthentication.FormsCookieName] is HttpCookie cookie)
    {
        var ticket = FormsAuthentication.Decrypt(cookie.Value);
        if (ticket != null)
        {
            var roles = ticket.UserData.Split(',');
            var identity = new FormsIdentity(ticket);
            var principal = new System.Security.Principal.GenericPrincipal(identity, roles);
            Context.User = principal;
        }
    }
}

// 頁面/類別層級授權
// web.config

  
    
      
      
    
  


// 程式碼檢查
if (User.IsInRole("Admin")) { ... }

無 Cookie / 行動裝置支援 (Cookieless)


 
// URL 變為 /(F(EncryptedTicket))/Login.aspx
// 注意:URL 洩露風險高,僅建議無 Cookie 環境使用

機器金鑰 叢集部署必設



多台伺服器**必須共用相同 machineKey**,否則 Ticket 解密失敗導致使用者頻繁被登出。

安全性最佳實務

  • HTTPS 全站強制:`requireSSL="true"` + HSTS Header。
  • HttpOnly + Secure Cookie:防止 XSS 竊取。
  • 密碼雜湊:永不儲存明文,使用 BCrypt / Argon2 / PBKDF2 (ASP.NET Core 內建 `IPasswordHasher`)。
  • 防暴力破解:失敗鎖定、CAPTCHA、IP 限流。
  • Session Fixation 防護:登入成功後 `Session.Abandon()` + 新 SessionID。
  • 登出清理:`FormsAuthentication.SignOut()` + `Session.Clear()` + `Response.Cookies.Delete`。

遷移至 ASP.NET Core Identity

新專案請直接使用 **ASP.NET Core Identity**:內建 EF Core 整合、雙因子驗證、外部登入、Token 刷新、GDPR 合規,架構更現代且長期支援。

Forms Authentication 雖屬經典技術,理解其 Ticket/Cookie/Module 運作原理,對維護舊系統、設計自訂驗證機制、轉型現代架構皆有幫助。

copyright © 萬盛學電腦網 all rights reserved