目錄
- 概述
- 核心概念
- TGC (Ticket Granting Cookie)
- TGT (Ticket Granting Ticket)
- ST (Service Ticket)
- 架構設計
- 整體架構
- 存儲架構
- 安全機制
- 工作流程
- 完整登錄時序
- 流程步驟詳解
- 技術實現
- 會話管理
- 數據同步問題
- 最佳實踐
- 參考資料
概述
CAS (Central Authentication Service) 是一個企業級單點登錄解決方案,為多個應用系統提供統一的身份認證服務。通過CAS,用戶只需要在認證中心登錄一次,即可訪問所有受保護的應用系統,無需重復登錄。
核心特性
- 單點登錄:用戶只需登錄一次即可訪問所有授權應用
- 安全可靠:基于票據機制,確保認證過程的安全性
- 集中管理:統一的用戶認證和會話管理
- 應用解耦:應用系統無需關心具體的認證邏輯
適用場景
- 企業內部多個應用系統的統一登錄
- 微服務架構中的身份認證
- 跨域應用的單點登錄需求
- 需要集中用戶管理的復雜系統
核心概念
CAS采用基于票據的認證機制,通過三種不同類型的票據來實現安全可靠的單點登錄功能。
TGC (Ticket Granting Cookie)
TGC是CAS會話的唯一標識符,是連接用戶瀏覽器和CAS服務器的橋梁。
基本特性
- 本質:CAS服務器session的唯一標識(sessionId)
- 作用:作為TGT的key,用于查找對應的用戶會話信息
- 存儲位置:以cookie形式保存在用戶瀏覽器中
- 域限制:只在CAS服務器域下有效(如:sso.company.com)
- 傳輸方式:每個HTTP請求自動攜帶
技術實現
TGC → sessionId (key)
TGT → session content (value)
關系:TGC:TGT = key:value
TGT (Ticket Granting Ticket)
TGT是CAS為用戶簽發的登錄憑證,是驗證用戶登錄成功的核心票據。
存儲機制
重要說明:TGT本身不是存儲在cookie中,而是存儲在CAS服務器端。
- 服務器端存儲:TGT存儲在CAS服務器端,具體存儲位置取決于配置
- Cookie關聯:通過TGC作為key來查找對應的TGT
- 安全考慮:TGT包含敏感的用戶信息,不能直接暴露在客戶端
數據結構
// 瀏覽器Cookie中
TGC = "CASTGC-xxxx-yyyy-zzzz" // 僅僅是一個sessionId// CAS服務器端
TGT = {user: "zhang_san",roles: ["admin", "user"],permissions: [...],expireTime: 1640995200,services: ["app1", "app2"]
}// 關聯關系
服務器緩存[TGC] → TGT對象
設計原理
為什么TGT不能存儲在Cookie中?
- 安全性:TGT包含敏感的用戶信息和權限數據
- 大小限制:Cookie有4KB大小限制,TGT數據可能超出限制
- 篡改風險:客戶端存儲容易被篡改,服務器端存儲更安全
- 集中管理:服務器端存儲便于統一管理和控制
ST (Service Ticket)
ST是用戶訪問特定服務時提供的服務票據,是CAS安全架構的核心組件。
核心作用
ST實際上是一個臨時通行證,用于解決以下關鍵問題:
- 安全隔離:TGT只能在CAS服務器內部使用,不能直接傳遞給各個應用系統
- 服務授權:每個ST只對特定的服務有效,實現了服務級別的訪問控制
- 防止重放攻擊:一次性使用特性,防止票據被截獲后重復使用
設計原理
為什么需要ST而不直接用TGT?
- 如果直接傳遞TGT給應用系統,TGT可能被惡意應用竊取
- TGT一旦泄露,攻擊者可以訪問用戶的所有授權服務
- ST將TGT的權限范圍限制在單個服務內
TGT(全局權限) → ST(單服務權限) → 應用系統驗證↓ ↓不離開CAS服務器 可以安全傳輸
生命周期
- 生成時機:用戶訪問服務時發現沒有有效的本地會話
- 獲取流程:302重定向到CAS服務器獲取ST
- 使用方式:攜帶ST重定向回目標服務
- 驗證過程:應用系統將ST發送給CAS服務器驗證
- 銷毀時機:驗證完成后立即銷毀,確保一次性使用
實際應用場景
假設用戶要訪問郵箱系統:
- 用戶已通過CAS登錄(擁有TGT)
- 訪問郵箱系統時,CAS為郵箱系統專門生成ST-mail
- 郵箱系統收到ST-mail后,向CAS驗證
- CAS確認ST-mail有效且是為郵箱系統生成的
- 郵箱系統獲得用戶身份信息,建立本地會話
- ST-mail被銷毀,無法再次使用
票據關系對比
特性 | TGT | ST |
---|---|---|
作用范圍 | 全局,所有服務 | 單個服務 |
存儲位置 | CAS服務器內部 | URL參數傳輸 |
生命周期 | 用戶會話期間 | 一次性使用 |
安全等級 | 高,不離開CAS | 中,可傳輸但限制使用 |
用途 | 證明用戶身份 | 授權訪問特定服務 |
架構設計
整體架構
┌─────────────────────────────────────┐
│ CAS服務器 │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ 認證模塊 │ │ 票據管理 │ │
│ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ 會話管理 │ │ 安全策略 │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────┘│├─────────────────────────┐│ │
┌─────────────▼─────────────┐ ┌─────────▼─────────────┐
│ 應用系統A │ │ 應用系統B │
│ ┌─────────────────┐ │ │ ┌─────────────────┐ │
│ │ CAS客戶端 │ │ │ │ CAS客戶端 │ │
│ └─────────────────┘ │ │ └─────────────────┘ │
└───────────────────────────┘ └───────────────────────┘
存儲架構
CAS系統采用多層存儲架構,包括瀏覽器Cookie存儲和多個服務器端Session存儲。
完整存儲架構
瀏覽器Cookie存儲 服務器端Session存儲
─────────────────────────────────────────────────────────────────CAS域 (sso.company.com): CAS服務器端:
├── TGC="CASTGC-xxxx-yyyy" ├── 緩存[TGC] → TGT對象
└── 作用:全局登錄狀態標識 └── 包含:用戶信息、權限、有效期應用A域 (mail.company.com): 應用A服務器端:
├── JSESSIONID="APP-A-session" ├── 緩存[JSESSIONID] → ApplicationSession
└── 作用:郵箱系統本地會話標識 └── 包含:用戶信息、應用數據、權限映射應用B域 (oa.company.com): 應用B服務器端:
├── JSESSIONID="APP-B-session" ├── 緩存[JSESSIONID] → ApplicationSession
└── 作用:OA系統本地會話標識 └── 包含:用戶信息、應用數據、權限映射
應用端會話管理
除了CAS域的TGC,每個應用系統也會在自己的域下維護獨立的會話:
應用域Cookie的作用:
- 本質:應用系統自己的session cookie
- 域名:存儲在應用系統的域下(如:mail.company.com)
- 內容:應用系統的本地會話標識
- 目的:維護用戶在該應用中的登錄狀態
應用服務端存儲內容:
// 應用服務端Session存儲示例
ApplicationSession = {sessionId: "APP-A-session-id", // 對應cookie中的值userId: "zhang_san", // 從CAS獲取的用戶身份userInfo: { // 從CAS獲取的用戶信息name: "張三",email: "zhangsan@company.com",roles: ["admin", "user"]},appSpecificData: { // 應用特定的會話數據currentPage: "/inbox",preferences: {...},businessContext: {...}},permissions: ["read_mail", "send_mail"], // 應用內權限loginTime: 1640995200,lastAccessTime: 1640995800,expireTime: 1640999400
}
存儲關系對比
組件 | Cookie存儲 | 服務器端存儲 | 存儲內容 |
---|---|---|---|
CAS | TGC (sessionId) | TGT對象 | 用戶身份、全局權限、有效期 |
應用A | JSESSIONID | ApplicationSession | 用戶信息+應用特定數據 |
應用B | JSESSIONID | ApplicationSession | 用戶信息+應用特定數據 |
安全機制
- 票據時效性:所有票據都有明確的有效期
- 一次性使用:ST只能使用一次,防止重放攻擊
- HTTPS傳輸:所有敏感信息通過HTTPS傳輸
- 會話管理:完善的會話超時和清理機制
- 域隔離:不同域名的cookie自然隔離
- 權限分級:全局權限(TGT)和服務權限(ST)的分離
工作流程
完整登錄時序
用戶 → 應用系統(SP) → CAS服務器 → 應用系統(SP) → 用戶│ │ │ │ ││ ①訪問受保護資源 │ │ ││ │ │ │ ││ ②重定向到CAS │ │ ││ │ │ │ ││ ③請求登錄頁面────────→ │ ││ │ │ │ ││ ④返回登錄表單←──────── │ ││ │ │ │ ││ ⑤提交登錄信息────────→ │ ││ │ │ │ ││ ⑥驗證并生成TGT │ │ ││ │ │ │ ││ ⑦返回ST并重定向──────→ │ ││ │ │ │ ││ ⑧驗證ST請求─────────────────────────→ ││ │ │ │ ││ ⑨返回驗證結果←────────────────────── ││ │ │ │ ││ ⑩建立會話并訪問──────────────────────────────→
流程步驟詳解
1. 用戶訪問應用系統
用戶通過瀏覽器訪問受保護的應用系統(Service Provider, SP)。
2. SP檢測未登錄狀態
SP檢測到用戶未登錄,重定向用戶到CAS服務器進行身份驗證。
3. 用戶請求登錄頁面
用戶的瀏覽器向CAS服務器發送請求,請求登錄頁面。
4. CAS提供登錄表單
CAS服務器響應,返回包含登錄表單的HTML頁面給用戶。
5. 用戶提交登錄信息
用戶在表單中輸入用戶名和密碼,提交表單信息回CAS服務器。
6. CAS驗證用戶憑據
CAS服務器驗證用戶的用戶名和密碼。驗證成功后:
- 生成TGT(Ticket-Granting Ticket)
- 將TGT存儲在服務器的票據存儲中
- 將TGT對應的cookie(TGC)發送給用戶瀏覽器
7. 重定向回SP并攜帶service ticket
用戶瀏覽器被重定向回SP,URL中攜帶一個service ticket(ST)。ST是基于當前服務生成的,用于一次性使用。
8. SP驗證service ticket
SP接收到ST后,向CAS服務器發送驗證請求,包含ST以及SP自己的標識信息。
9. CAS驗證service ticket有效性
CAS服務器驗證ST的有效性(檢查TGT和ST的一致性等),確認無誤后,向SP返回驗證結果,通常包含用戶的身份信息或確認驗證成功的標志。
10. SP建立用戶會話
SP根據CAS的驗證結果,為用戶建立會話,允許用戶訪問受保護的資源。
11. 用戶訪問受保護資源
用戶可以直接與SP交互,訪問受保護的內容,直到會話結束或超時。
多應用訪問流程
用戶在完成首次登錄后,訪問其他應用的流程會更加簡化:
-
首次訪問應用A:
- 檢查mail.company.com域下的cookie → 無會話
- 重定向到CAS進行認證
-
CAS認證成功:
- 在sso.company.com域下設置TGC
- 生成ST重定向回應用A
-
應用A驗證ST:
- 驗證ST成功后,在mail.company.com域下設置自己的session cookie
- 建立用戶在應用A的本地會話
-
后續訪問應用A:
- 直接檢查mail.company.com域下的cookie
- 有有效會話則直接訪問,無需再次認證
-
訪問應用B:
- 檢查oa.company.com域下的cookie → 無會話
- 重定向到CAS,CAS檢查TGC → 已登錄
- 直接生成ST重定向回應用B(無需重新輸入密碼)
技術實現
會話管理
應用會話的特點
重要澄清:應用服務器的Session不是CAS的緩存,而是包含兩部分數據:
- 從CAS獲取的用戶信息(一次性獲取)
- 應用自己產生的業務數據(持續更新)
數據獲取方式
// ST驗證時,CAS返回的用戶信息(一次性)
CASValidationResponse = {userId: "zhang_san",attributes: {name: "張三",email: "zhangsan@company.com", roles: ["admin", "user"]}
}// 應用服務器基于此信息創建自己的Session
ApplicationSession = {// 從CAS獲取的用戶信息(不變)userId: "zhang_san",userInfo: {...},// 應用自己產生的數據(持續變化)currentPage: "/inbox", // 用戶當前頁面unreadCount: 5, // 未讀消息數preferences: {...}, // 用戶偏好設置businessContext: {...}, // 業務上下文lastOperation: "send_mail", // 最后操作// 應用自己的會話管理loginTime: 1640995200,lastAccessTime: 1640995800,expireTime: 1640999400
}
應用與CAS的交互模式
應用服務器 ←→ CAS服務器的交互:
1. ST驗證時:獲取用戶信息(一次性)
2. 單點登出時:通知會話失效(事件驅動)
3. 正常運行時:相互獨立,無實時交互應用服務器內部的Session管理:
1. 基于CAS用戶信息創建會話
2. 獨立管理應用業務數據
3. 獨立控制會話超時和清理
數據同步問題
同步延遲現象
如果用戶在CAS中修改了信息(角色、權限、郵箱等),應用服務器不會立即知道這些變化。
問題原因
時間線:
T1: 用戶通過ST驗證,應用獲得用戶信息快照
T2: 用戶在CAS中修改了角色(admin → user)
T3: 應用服務器仍然認為用戶是admin
T4: 直到用戶重新登錄或會話超時,應用才會獲得新信息
實際影響
// 場景:用戶權限被管理員撤銷
CAS系統:
用戶角色: admin → user (已修改)應用服務器Session(仍是舊信息):
ApplicationSession = {userId: "zhang_san",roles: ["admin"], // 舊信息!permissions: ["admin_all"] // 舊權限!
}// 結果:用戶仍然可以執行admin操作
利弊分析
優點(設計考慮):
- 性能優化:避免每次請求都查詢CAS
- 系統穩定:應用不依賴CAS的實時可用性
- 網絡效率:減少CAS服務器壓力
缺點(安全風險):
- 權限延遲:權限變更不能立即生效
- 信息過期:用戶信息可能過期
- 安全隱患:被撤銷權限的用戶可能繼續操作
最佳實踐
1. 會話超時策略
// 設置較短的會話超時時間
ApplicationSession.expireTime = 30分鐘; // 強制重新認證
2. 實時權限驗證
// 關鍵操作時重新驗證權限
if (criticalOperation) {// 向CAS或權限系統重新查詢當前權限currentPermissions = permissionService.getCurrentPermissions(userId);
}
3. 消息推送機制
// CAS推送用戶信息變更事件
@EventListener
public void onUserInfoChanged(UserInfoChangedEvent event) {// 更新或清除相關用戶的SessionsessionManager.invalidateUserSessions(event.getUserId());
}
4. 定期同步機制
// 定期從CAS同步用戶信息
@Scheduled(fixedRate = 300000) // 5分鐘
public void syncUserInfoFromCAS() {// 批量同步活躍用戶信息
}
5. 實施建議
- 敏感操作實時驗證:重要操作前重新驗證權限
- 合理的會話超時:平衡性能和安全性
- 監控和審計:記錄權限變更和訪問日志
- 分層權限設計:區分長期權限和臨時權限
6. 票據管理
- TGT的生命周期管理
- ST的一次性使用控制
- 票據的安全存儲和檢索
7. 會話同步
- 多應用系統間的會話狀態同步
- 單點登出的實現
- 會話超時處理
8. 安全考慮
- 防止會話劫持
- 票據偽造防護
- 傳輸加密保護
9. 性能優化
- 票據緩存策略
- 數據庫連接池管理
- 負載均衡支持
參考資料
技術文檔
- CAS官方文檔
- CAS協議規范
實現案例
- CAS登錄原理和實現
- CAS單點登錄詳解
- CAS架構設計與實現
相關技術
- Spring Security CAS集成
- SAML vs CAS比較
本文檔詳細介紹了CAS單點登錄的完整架構設計和實現要點,涵蓋了從基礎概念到技術實現的全過程。通過理解CAS的票據機制、存儲架構和工作流程,可以更好地設計和實現企業級的單點登錄解決方案。