首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET Cookie 集合封裝:定義、建立、刪除、強型別存取完整實作

     編輯:ASP.NET 基礎

為何要封裝 Cookie 集合?

  • 單一 Cookie 存放多個鍵值 (UserId=123&Role=Admin&Theme=Dark),減少 Cookie 數量與請求標頭大小。
  • 集中管理過期時間、加密、HttpOnly、Secure、SameSite 設定。
  • 提供強型別屬性 (CurrentUser.Id),避免魔術字串散落各處。
  • 統一處理 null、序列化、編碼細節。

完整封裝類別

using System;
using System.Web;

public static class AuthCookie
{
    private const string CookieName = "AuthCookie";
    private static HttpResponse Response => HttpContext.Current.Response;
    private static HttpRequest Request => HttpContext.Current.Request;

    // 內部存取器:自動建立/取得 HttpCookie 實例
    private static HttpCookie Cookie
    {
        get => Request.Cookies[CookieName];
        set
        {
            if (value == null) return;
            // 移除舊 Cookie 避免重複
            if (Request.Cookies[CookieName] != null)
                Request.Cookies.Remove(CookieName);
            Response.Cookies.Add(value);
        }
    }

    // 新建空白 Cookie (預設設定)
    private static HttpCookie NewCookie()
    {
        var c = new HttpCookie(CookieName)
        {
            HttpOnly = true,
            Secure = HttpContext.Current.Request.IsSecureConnection, // 僅 HTTPS 傳送
            SameSite = SameSiteMode.Lax,
            Expires = DateTime.Now.AddDays(30)
        };
        return c;
    }

    // 公開屬性:登入狀態
    public static bool IsLoggedIn
    {
        get => Cookie != null && bool.TryParse(Cookie.Values["IsLoggedIn"], out var b) && b;
        set
        {
            var c = Cookie ?? NewCookie();
            c.Values["IsLoggedIn"] = value.ToString();
            Cookie = c;
        }
    }

    // 公開屬性:使用者 ID (int)
    public static int UserId
    {
        get => Cookie != null && int.TryParse(Cookie.Values["UserId"], out var id) ? id : 0;
        set
        {
            var c = Cookie ?? NewCookie();
            c.Values["UserId"] = value.ToString();
            Cookie = c;
        }
    }

    // 公開屬性:角色清單 (逗號分隔)
    public static string Roles
    {
        get => Cookie?.Values["Roles"] ?? string.Empty;
        set
        {
            var c = Cookie ?? NewCookie();
            c.Values["Roles"] = value;
            Cookie = c;
        }
    }

    // 公開屬性:偏好主題
    public static string Theme
    {
        get => Cookie?.Values["Theme"] ?? "Light";
        set
        {
            var c = Cookie ?? NewCookie();
            c.Values["Theme"] = value;
            Cookie = c;
        }
    }

    // 登出:移除 Cookie
    public static void SignOut()
    {
        if (Cookie != null)
        {
            // 設為過期即刪除
            Cookie.Expires = DateTime.Now.AddDays(-1);
            Response.Cookies.Set(Cookie);
        }
    }

    // 更新過期時間 (滑動過期)
    public static void Renew()
    {
        if (Cookie != null)
        {
            Cookie.Expires = DateTime.Now.AddDays(30);
            Response.Cookies.Set(Cookie);
        }
    }
}

使用範例

登入成功時

protected void btnLogin_Click(object sender, EventArgs e)
{
    var user = UserService.Validate(txtUser.Text, txtPwd.Text);
    if (user != null)
    {
        AuthCookie.IsLoggedIn = true;
        AuthCookie.UserId = user.Id;
        AuthCookie.Roles = string.Join(",", user.Roles);
        AuthCookie.Theme = user.PreferredTheme;
        Response.Redirect("~/Dashboard.aspx");
    }
    else
    {
        lblError.Text = "帳號密碼錯誤";
    }
}

頁面驗證登入

protected void Page_Load(object sender, EventArgs e)
{
    if (!AuthCookie.IsLoggedIn)
    {
        Response.Redirect("~/Login.aspx?ReturnUrl=" + Server.UrlEncode(Request.RawUrl));
    }
    else
    {
        // 取得強型別值
        int uid = AuthCookie.UserId;
        bool isAdmin = AuthCookie.Roles.Contains("Admin");
        litWelcome.Text = $"歡迎,使用者 {uid}";
    }
}

登出

protected void btnLogout_Click(object sender, EventArgs e)
{
    AuthCookie.SignOut();
    Response.Redirect("~/Login.aspx");
}

進階:加密敏感欄位


// 簡易 AES 加密 (生產請用 DataProtectionProvider / ASP.NET Core DataProtection)
private static string Encrypt(string plain) => Convert.ToBase64String(ProtectedData.Protect(Encoding.UTF8.GetBytes(plain), null, DataProtectionScope.CurrentUser));
private static string Decrypt(string cipher) => Encoding.UTF8.GetString(ProtectedData.Unprotect(Convert.FromBase64String(cipher), null, DataProtectionScope.CurrentUser));

// 屬性存取時自動加解密
public static string SensitiveToken
{
    get => Cookie != null ? Decrypt(Cookie.Values["Token"]) : null;
    set
    {
        var c = Cookie ?? NewCookie();
        c.Values["Token"] = Encrypt(value);
        Cookie = c;
    }
}

安全性檢查清單

項目 建議設定
HttpOnly true (防 XSS 竊取)
Secure true (僅 HTTPS 傳送,生產環境強制)
SameSite Lax (平衡 CSRF 防護與跨站導向) / Strict (嚴格)
Domain 明確設定 (如 .example.com) 而非預設
Path / (全站) 或特定應用程式路徑
Expires 滑動過期 (每次請求 Renew) 或固定 30 天

常見問題

  1. Request.Cookies.Remove 後仍存在:只移除集合參考,必須設定 Expires = 過去日期 並 Response.Cookies.Add/Set 才能真正刪除瀏覽器端 Cookie。
  2. 子網域共享:Domain = ".example.com" 並確保所有子站應用程式金鑰 machineKey 一致 (加密/驗證用)。
  3. 4KB 限制:單一 Cookie 總大小 (含名稱、值、屬性) 不超過 4096 bytes;集合寫法可減少 Cookie 數量但總容量不變。
  4. 編碼問題:值含分號、逗號、等號時會干擾解析,建議 HttpUtility.UrlEncode 儲存、UrlDecode 讀取。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved