參考園友文章《單點登陸(SSO)組件的設計與實現》,典型流程:
子站點 A Session 尚未過期,子站點 B Session 已過期,用戶未登出。此時認證中心在線列表該保留還是移除 UID?若移除,A 仍有效卻被判定離線;若保留,B 過期卻仍顯示在線。
URL 參數傳遞 Token (如 ?uid=123) 極易被竊取。攻擊者在另一瀏覽器/機器帶上相同 uid 訪問子站點,認證中心驗證通過 → **橫向越權登入**。
用戶在站點 A 登入後,於**新分頁/新視窗**輸入站點 B 網址。此時:
SSO 核心難點在於:**如何在「無 Session、無 URL Token」的冷啟動請求中,識別用戶身份?**
答案只有一個:**瀏覽器自動攜帶的 Cookie**。
.example.com)。SSO_TOKEN,Value: 加密後的 UserId|ExpireTime|Signature。HttpOnly、Secure、SameSite=Lax。// 子站點 Global.asax / Middleware
public void OnRequest()
{
// 1. 檢查本地 Session
if (Session["UserId"] != null) return; // 已登入
// 2. 檢查 URL Token (重導向回調場景)
string token = Request.QueryString["token"];
if (!string.IsNullOrEmpty(token) && ValidateTokenWithAuthCenter(token))
{
EstablishLocalSession(token);
return;
}
// 3. 核心:讀取跨域 Cookie
string ssoCookie = Request.Cookies["SSO_TOKEN"]?.Value;
if (!string.IsNullOrEmpty(ssoCookie) && ValidateTokenWithAuthCenter(ssoCookie))
{
EstablishLocalSession(ssoCookie); // 靜默登入!
return;
}
// 4. 完全未授權 → 重導向認證中心登入頁
RedirectToAuthCenter();
}
UserId、ExpireTime、Signature。ExpireTime > Now。UserId 仍在線。| 難題 | 解決機制 |
|---|---|
| Session 過期不一致 | 認證中心在線列表 **唯一真實來源**;子站點 Session 只是緩存,過期即重新驗證 Cookie 同步狀態 |
| Token 暴露盜用 | Cookie HttpOnly 防 XSS 竊取;SameSite=Lax 防 CSRF;簽名防篡改;**綁定 IP/UA 指紋** 進一步降低風險 |
| 新分頁無法識別 | 瀏覽器自動攜帶根域 Cookie → 子站點冷啟動即可靜默驗證 → **零感知單點登入** |
// 產生 Token 時
string fingerprint = Hash(UserIP + UserAgent);
string token = Encrypt($"{userId}|{expire}|{fingerprint}");
// 驗證時
var parts = Decrypt(token).Split('|');
string currentFp = Hash(Request.UserHostAddress + Request.UserAgent);
if (parts[2] != currentFp) throw new SecurityException("Device mismatch");
若用戶 IP 變更 (如切換網路),需重新登入,極大提升安全性。
/logout。/sso/logout?token=xxx (或透過 SignalR/WebSocket 推送)。SSO 成敗在於**「冷啟動識別」**。傳統流程依賴重導向傳 Token,無法解決新分頁/新視窗場景。**跨域共享 Cookie + 簽名驗證 + 在線列表二次確認** 是業界標準解法 (如 CAS、IdentityServer、Keycloak 皆採用類似機制)。配合 IP/裝置指紋、短效 Token + Refresh Token、集中式 Session 儲存 (Redis),可構建企業級高安全 SSO 系統。