首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

單點登入踢人策略:新登入自動登出舊 Session 的實作方案

     編輯:程式設計疑難解答

需求

同一帳號在不同裝置/瀏覽器重複登入時,新登入成功,舊 Session 自動失效,並在舊裝置顯示「異地登入」彈窗導向登出頁。

核心架構:Session ID 註冊表 + 輪詢檢查

伺服器端資料結構

// 記憶體或 Redis:userId -> 當前有效的 sessionId
ConcurrentDictionary<string, string> userSessionMap = new();

登入流程

  1. 使用者提交帳密驗證通過。
  2. 建立新 Session,取得 newSessionId。
  3. 檢查 userSessionMap[userId] 是否存在 oldSessionId。
  4. 若存在且 oldSessionId != newSessionId:
    • 標記舊 Session 為「已被踢」(如在 Session 中設 IsKicked = true 或從 Session Store 移除)。
    • 更新 userSessionMap[userId] = newSessionId。
  5. 將 newSessionId 寫入回應 Cookie。

舊裝置偵測被踢(前端輪詢)

// 頁面載入後啟動輪詢
setInterval(async () => {
    const res = await fetch('/api/check-session', { credentials: 'include' });
    const data = await res.json();
    if (data.kicked) {
        alert('您的帳號在其他裝置登入,將被強制登出。');
        location.href = '/logout?reason=kicked';
    }
}, 10000); // 每 10 秒檢查一次

後端檢查端點

[HttpGet]
public IActionResult CheckSession()
{
    var currentSessionId = HttpContext.Session.Id;
    var userId = HttpContext.Session.GetString("UserId");
    var validSessionId = userSessionMap.GetValueOrDefault(userId);
    
    return Json(new { kicked = (validSessionId != currentSessionId) });
}

替代方案:SignalR 即時推送(無需輪詢)

  • 登入時呼叫 Clients.User(oldSessionId).SendAsync("ForceLogout")。
  • 前端建立 SignalR 連線監聽 ForceLogout 事件,收到即彈窗跳轉。
  • 適合高即時性需求,但增加伺服器連線資源。

安全性補充

  • Session ID 應使用加密隨機產生,防止猜測。
  • 登出時同步清除 userSessionMap 對應項目。
  • 若使用分散式 Session(Redis),確保原子操作(Lua 腳本)避免競態。

總結

核心在於「集中式 Session ID 註冊表」配合「前端輪詢或 SignalR 推送」。登入時更新註冊表並標記舊 Session,舊裝置透過定期檢查或即時訊號感知被踢並導向登出。

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