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

ASP.NET 2.0 防止同一使用者重複登入:Cache 搭配 Session Timeout 實作

     編輯:關於ASP.NET

需求與挑戰

系統需確保同一帳號同一時間僅能在一處登入。挑戰在於:**如何偵測使用者「離開系統」**?使用者可能直接關閉瀏覽器、關閉分頁、網路中斷,無法觸發明確的登出事件。

解決方案:Cache + Session Timeout 同步失效

核心思路:

  1. 登入成功時,以使用者帳號為 Key 寫入 Cache,值可為帳號本身或登入時間。
  2. 設定 Cache 過期時間與 Session.Timeout 完全一致 (滑動過期)。
  3. 當 Session 因逾時被伺服器回收,對應的 Cache 項目同步失效,代表使用者已「離開」。
  4. 後續登入嘗試檢查 Cache 是否存在,存在即拒絕 (重複登入),不存在則允許並建立新 Cache。

完整實作程式碼 (登入按鈕 Click 事件)

Protected Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click
    Dim userName As String = txtUserName.Text.Trim()
    If String.IsNullOrEmpty(userName) Then
        lblMsg.Text = "請輸入帳號"
        Return
    End If
    
    ' 1. 驗證帳號密碼 (略,假設通過)
    If Not ValidateUser(userName, txtPassword.Text) Then
        lblMsg.Text = "帳號或密碼錯誤"
        Return
    End If
    
    ' 2. 檢查 Cache 中是否已有該使用者
    Dim cacheKey As String = "Login_" & userName
    Dim existing As Object = Cache(cacheKey)
    
    If existing IsNot Nothing Then
        ' 已有登入紀錄 → 重複登入
        lblMsg.Text = "該帳號已在其他地方登入,請先登出或稍後再試。"
        Return
    End If
    
    ' 3. 首次登入:建立 Cache,滑動過期時間 = Session Timeout
    Dim sessionTimeout As TimeSpan = TimeSpan.FromMinutes(Session.Timeout) ' 預設 20 分鐘
    Cache.Insert(cacheKey, userName, Nothing, 
                 Cache.NoAbsoluteExpiration, 
                 sessionTimeout, 
                 CacheItemPriority.NotRemovable, 
                 Nothing)
    
    ' 4. 建立 Session 標記登入狀態
    Session("UserName") = userName
    Session("LoginTime") = DateTime.Now
    
    ' 5. 導向主頁
    Response.Redirect("Main.aspx")
End Sub

關鍵細節解析

  • Cache Key 前綴:"Login_" 避免與其他快取項目衝突。
  • 滑動過期:Cache.NoAbsoluteExpiration + sessionTimeout 表示「最後存取後 N 分鐘未存取則過期」,與 Session 機制一致。
  • CacheItemPriority.NotRemovable:防止記憶體壓力下被主動移除,確保同步性。
  • Session 與 Cache 同步:Session 逾時 → Session_End 觸發 (InProc 模式) → 但 Cache 依靠自身滑動過期自動失效,**無需額外程式碼清理**。

登出時主動清除 Cache

Protected Sub btnLogout_Click(sender As Object, e As EventArgs) Handles btnLogout.Click
    Dim userName As String = CStr(Session("UserName"))
    If Not String.IsNullOrEmpty(userName) Then
        Cache.Remove("Login_" & userName)
    End If
    Session.Abandon()
    Response.Redirect("Login.aspx")
End Sub

進階:Web Farm / 多伺服器環境

InProc Session + 本機 Cache **不適用** 多伺服器部署。解決方案:

  • Session State 模式改為 StateServer 或 SQLServer:所有節點共享 Session。
  • Cache 改用分散式快取 (Redis、Memcached、AppFabric):以相同 Key/滑動過期邏輯實現跨節點同步。
  • 資料庫表法:建立 UserSessions(UserName, LastActivity, ServerNode) 表,登入寫入/更新,定期清理逾期記錄,查詢判斷是否重複登入。

常見誤區

  1. 使用 Application 儲存登入狀態:Application 不支援滑動過期,無法自動偵測使用者離開。
  2. Cache 設定絕對過期:DateTime.Now.AddMinutes(20) 會導致使用者操作中途被強制登出。
  3. 忽略 Session 模式影響:StateServer/SQLServer 模式下 Session_End **不會觸發**,但 Cache 滑動過期機制仍有效 (需分散式快取)。

結語

利用 Cache.Insert 搭配 Session.Timeout 滑動過期,配合 CacheItemPriority.NotRemovable,即可用極少程式碼實現「同一帳號單一登入」功能。關鍵在於理解 Cache 與 Session 過期機制的同步關係,並在多伺服器環境下升級為分散式快取方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved