同一帳號在不同裝置/瀏覽器重複登入時,新登入成功,舊 Session 自動失效,並在舊裝置顯示「異地登入」彈窗導向登出頁。
// 記憶體或 Redis:userId -> 當前有效的 sessionId
ConcurrentDictionary<string, string> userSessionMap = new();
newSessionId。userSessionMap[userId] 是否存在 oldSessionId。oldSessionId != newSessionId:
IsKicked = true 或從 Session Store 移除)。userSessionMap[userId] = newSessionId。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) });
}
Clients.User(oldSessionId).SendAsync("ForceLogout")。ForceLogout 事件,收到即彈窗跳轉。userSessionMap 對應項目。核心在於「集中式 Session ID 註冊表」配合「前端輪詢或 SignalR 推送」。登入時更新註冊表並標記舊 Session,舊裝置透過定期檢查或即時訊號感知被踢並導向登出。