跨域分散式系統單點登錄的實現(CAS單點登錄)
1. 概述
上一次我們聊了一下《使用Redis實現分散式會話》,原理就是使用 客戶端Cookie + Redis 的方式來驗證用戶是否登錄。
如果分散式系統中,只是對Tomcat做了負載均衡,或者所有的子系統都在同一個二級域名下,則 客戶端Cookie + Redis 的方式是可以支援驗證用戶是否登錄的。
如果分散式系統中包含了不同域名的子系統,之前的 客戶端Cookie + Redis 的方式就不支援了,因為二級域名不同,Cookie無法共享。
例如:瀏覽器在子系統A的二級域名中保存了Cookie,在訪問子系統B時,無法從Cookie中拿到數據,因此沒有依據判斷用戶是否登錄。
此時我們就需要引入CAS(中央認證服務),讓CAS幫助我們實現跨域單點登錄。
今天我們就來聊聊這個跨域分散式系統單點登錄的實現。
2. 場景說明
子系統A域名:www.a.com
子系統B域名:www.b.com
CAS系統域名:www.cas.com
當子系統A和子系統B都未登錄,則客戶端請求時需要登錄。
當客戶端請求子系統A觸發了登錄,且登錄成功,則客戶端再請求子系統B時,不需要登錄,可直接訪問。
3.概念說明
全局票據:一個全局唯一的uuid,存放在域名為 .cas.com 的 Cookie 中,是用戶已登錄的標識。
臨時票據:一個全局唯一的uuid,存放在Redis中,有過期時限,用於驗證用戶的身份。
4. 跨域單點登錄的實現邏輯
4.1 用戶訪問子系統A
用戶訪問子系統A的頁面,子系統A的頁面請求子系統A的後台介面,子系統A後台檢查當前系統的Cookie中是否存在用戶脫敏資訊。
因為從未登錄過,所以Cookie中是不存在用戶脫敏資訊的,子系統A後台再檢查參數中是否包含臨時票據,此時是沒有的,因此子系統A後台返回未登錄給客戶端。
客戶端將當前子系統A頁面的 url 作為參數,重定向到CAS系統的登錄頁面。
4.2 用戶在CAS系統登錄
重定向到CAS系統的登錄頁,登錄頁首先判斷客戶端在CAS系統的Cookie中,是否存在全局票據。
因為沒有登錄過,所以在CAS系統的Cookie中不存在全局票據,用戶需要填寫用戶名、密碼進行登錄。
用戶在CAS系統的登錄頁面,填寫用戶名、密碼後,提交登錄。
CAS系統後台,校驗用戶名、密碼,通過後,生成一個全局唯一的 uuid,作為全局票據。
將全局票據存儲在域名為 .cas.com 的 Cookie 中。
以全局票據為 key,用戶ID 為 value,存到 Redis 中。
以用戶ID為 key,用戶資訊為 value,存到 Redis 中。
再生成一個 uuid 作為臨時票據,以臨時票據為 key,臨時票據為 value,存儲到Redis中,5分鐘過期。
CAS系統返回臨時票據給客戶端。
客戶端將頁面重定向回子系統A的頁面,臨時票據作為參數攜帶。
4.3 再次訪問子系統A
頁面被重定向回子系統A的頁面。
子系統A攜帶臨時票據訪問子系統A的後台介面,後台檢查當前系統的Cookie中是否存在用戶脫敏資訊,仍然是不存在。
後台檢查參數中是否包含臨時票據,臨時票據是存在的,子系統A的後台調用CAS後台的用戶身份驗證介面,以臨時票據作為參數。
CAS用戶身份驗證介面,以臨時票據為key,從redis中獲取value,value不為空,則驗證成功。
從CAS系統的Cookie中得到全局票據,以全局票據為key,從Redis中得到用戶ID,然後從redis中得到用戶資訊,返給子系統A的後台。
子系統A拿到用戶資訊後,將其脫敏,存儲在域名為 .a.com 的 Cookie 中,然後完成介面邏輯。
子系統A再次訪問其他介面時,後台檢查當前系統的Cookie中是否存在用戶脫敏資訊,此時是存在的。
後台使用用戶脫敏資訊中的用戶ID到Redis中獲取完整的用戶資訊,然後完成介面邏輯。
如果Redis中用戶資訊不存在,則表示用戶已註銷登錄,則返回未登錄。
4.4 用戶訪問子系統B
用戶訪問子系統B,子系統B後台檢查當前系統的Cookie中是否存在用戶脫敏資訊,不存在。然後檢查是否存在臨時票據,也不存在。返回未登錄。
重定向到CAS系統的登錄頁面,子系統B頁面的 url 作為參數。
CAS系統後台,判斷在CAS系統的Cookie中,是否存在全局票據,此時是存在的,因為使用的是同一個客戶端。
CAS系統後台生成一個uuid作為臨時票據,以臨時票據為 key,臨時票據為 value,存儲到Redis中,5分鐘過期。
CAS系統返回臨時票據給客戶端。
客戶端將頁面重定向回子系統B的頁面,臨時票據作為參數攜帶。
子系統B攜帶臨時票據訪問子系統B的後台介面,後台檢查當前系統的Cookie中是否存在用戶脫敏資訊,仍然是不存在。
後台檢查參數中是否包含臨時票據,臨時票據是存在的,子系統B的後台調用CAS後台的用戶身份驗證介面,以臨時票據作為參數。
CAS用戶身份驗證介面,以臨時票據為key,從redis中獲取value,value不為空,則驗證成功。
從CAS系統的Cookie中得到全局票據,以全局票據為key,從Redis中得到用戶ID,然後從redis中得到用戶資訊,返給子系統B的後台。
子系統B拿到用戶資訊後,將其脫敏,存儲在域名為 .b.com 的 Cookie 中,然後完成介面邏輯。
這樣一來,用戶無感知的訪問了子系統B,不需要再次輸入用戶名、密碼去登錄。
4.5 用戶註銷
用戶註銷時,首先清空當前子系統中用戶脫敏資訊的Cookie。
然後訪問CAS系統的用戶註銷介面。
CAS系統,從Cookie中拿到全局票據,根據全局票據從Redis中得到用戶ID。
刪除Cookie中的全局票據。
從Redis中刪除 key 為 全局票據 的數據。
從Redis中刪除 key 為 用戶ID 的數據 。
4.6 總結
這裡用了一個小技巧,a.com 和 b.com 的 Cookie 無法共享,因此就在一個公共的 cas.com 中去存Cookie,然後再做一次身份校驗就可以了。
5. 綜述
今天簡單聊了一下跨域分散式系統單點登錄的實現,希望能對大家的工作有所幫助。
歡迎大家幫忙點贊、評論、加關注 :)
關注追風人聊Java,每天更新Java乾貨。