系統需確保同一帳號同一時間僅能在一處登入。挑戰在於:**如何偵測使用者「離開系統」**?使用者可能直接關閉瀏覽器、關閉分頁、網路中斷,無法觸發明確的登出事件。
核心思路:
Cache,值可為帳號本身或登入時間。Cache 過期時間與 Session.Timeout 完全一致 (滑動過期)。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
"Login_" 避免與其他快取項目衝突。Cache.NoAbsoluteExpiration + sessionTimeout 表示「最後存取後 N 分鐘未存取則過期」,與 Session 機制一致。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
InProc Session + 本機 Cache **不適用** 多伺服器部署。解決方案:
UserSessions(UserName, LastActivity, ServerNode) 表,登入寫入/更新,定期清理逾期記錄,查詢判斷是否重複登入。DateTime.Now.AddMinutes(20) 會導致使用者操作中途被強制登出。利用 Cache.Insert 搭配 Session.Timeout 滑動過期,配合 CacheItemPriority.NotRemovable,即可用極少程式碼實現「同一帳號單一登入」功能。關鍵在於理解 Cache 與 Session 過期機制的同步關係,並在多伺服器環境下升級為分散式快取方案。