跨域分布式系統單點登錄的實現(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的后台接口,子系統A后台檢查當前系統的Cookie中是否存在用戶ID。

因為從未登錄過,所以Cookie中是不存在用戶ID的,因此子系統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的頁面Ajax調用CAS后台的用戶身份驗證接口,以臨時票據作為參數。

CAS用戶身份驗證接口,以臨時票據為key,從redis中獲取value,value不為空,則驗證成功,然后清空Redis中的臨時票據。

從CAS系統的Cookie中得到全局票據,以全局票據為key,從Redis中得到用戶ID,返給子系統A的頁面。

子系統A的頁面拿到用戶ID后,存儲在域名為 .a.com 的 Cookie 中。

然后繼續完成業務接口邏輯。

 

子系統A再次訪問業務接口時,后台檢查當前系統的Cookie中是否存在用戶ID,此時是存在的。

后台使用用戶ID到Redis中獲取完整的用戶信息,然后完成接口邏輯。

如果Redis中用戶信息不存在,則表示用戶已注銷登錄,則返回未登錄。

 

4.4 用戶訪問子系統B

用戶訪問子系統B的頁面,子系統B的頁面檢查參數中是否包含臨時票據,此時是沒有的,則什么都不做。

子系統B的頁面調用子系統B的后台接口,子系統B的后台檢查當前系統的Cookie中是否存在用戶ID,不存在,返回未登錄。

重定向到CAS系統的登錄頁面,子系統B頁面的 url 作為參數。

CAS系統后台,判斷在CAS系統的Cookie中,是否存在全局票據,此時是存在的,因為使用的是同一個客戶端。

CAS系統后台生成一個uuid作為臨時票據,以臨時票據為 key,臨時票據為 value,存儲到Redis中,5分鍾過期。

CAS系統返回臨時票據給客戶端。

客戶端將頁面重定向回子系統B的頁面,臨時票據作為參數攜帶。

 

子系統B的頁面檢查參數中是否有臨時票據,此時是有的,則子系統B的頁面Ajax調用CAS后台的用戶身份驗證接口,以臨時票據作為參數。

CAS用戶身份驗證接口,以臨時票據為key,從redis中獲取value,value不為空,則驗證成功,然后清空Redis中的臨時票據。

從CAS系統的Cookie中得到全局票據,以全局票據為key,從Redis中得到用戶ID,返給子系統B的頁面。

子系統A的頁面拿到用戶ID后,存儲在域名為 .b.com 的 Cookie 中。

 

子系統B再次訪問業務接口時,后台檢查當前系統的Cookie中是否存在用戶ID,此時是存在的。

后台使用用戶ID到Redis中獲取完整的用戶信息,然后完成接口邏輯。

 

這樣一來,用戶無感知的訪問了子系統B,不需要再次輸入用戶名、密碼去登錄。

 

4.5 用戶注銷

用戶注銷時,首先清空當前子系統中用戶ID的Cookie。

然后子系統前端頁面Ajax訪問CAS系統的用戶注銷接口。

CAS系統,從Cookie中拿到全局票據,根據全局票據從Redis中得到用戶ID。

刪除Cookie中的全局票據。

從Redis中刪除 key 為 全局票據 的數據。

從Redis中刪除 key 為 用戶ID 的數據 。

 

4.6 總結

這里用了一個小技巧,a.com 和 b.com 的 Cookie 無法共享,因此就在一個公共的 cas.com 中去存Cookie,然后再做一次身份校驗就可以了。

 

5. 綜述

今天簡單聊了一下跨域分布式系統單點登錄的實現,希望能對大家的工作有所幫助。

歡迎大家幫忙點贊、評論、加關注 :)

關注追風人聊Java,每天更新Java干貨。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM