JAVA單點(diǎn)登錄有好多種方式,譬如用cookie的domain做,用中間代理做等等,但都需要自行做許多開發(fā)工作。而其中耶魯大學(xué)的開源項(xiàng)目CAS提供了一個一站式解決方案,只需很少的擴(kuò)展即可輕松實(shí)現(xiàn)企業(yè)級單點(diǎn)登錄?;A(chǔ)知識網(wǎng)上其他挺多的,這里我就不詳述了。本文通過分析http請求過程中http header,cookie等數(shù)據(jù)剖析了cas(非代理模式,默認(rèn)驗(yàn)證邏輯。其他如restletAPI等可擴(kuò)展邏輯本文不會覆蓋)的驗(yàn)證流程,在開發(fā)調(diào)試中提供了另一種方便的方式掌控整個流程的關(guān)鍵點(diǎn)。
Cas術(shù)語
TGT: ?cas服務(wù)端生成的每個用戶唯一的ticket。
TGC: ?cas服務(wù)端根據(jù)TGT生成的每個用戶的cookie,其value是TGT。
ST: ???cas服務(wù)端根據(jù)每個應(yīng)用,每個用戶生成的一個ticket,驗(yàn)證一次就銷毀。
Shiro: JAVA權(quán)限管理框架
Cas請求交互總圖

下面將通過兩個客戶端應(yīng)用A、B分別跟cas server端交互來詳述整個交互流程。本文基于CAS 4.x。 CAS 5.X默認(rèn)邏輯一致,只不過通過spring boot進(jìn)行了重新模塊劃分。
客戶端應(yīng)用A訪問跳轉(zhuǎn)Cas Server驗(yàn)證
http request:
GET ?http://uc.54315.com/myWhListManager
http response:
302 Found
Location:?https://passport.jzt.com/login?service=http://uc.54315.com/casuc
Cas client攔截請求發(fā)現(xiàn)session中無cas assertion(其實(shí)就是用戶名和ticket)并且沒有ST則跳轉(zhuǎn)CAS server(本項(xiàng)目由于用了shiro重寫攔截邏輯所以是判斷shiro中有沒有保存驗(yàn)證后的用戶信息), server端發(fā)現(xiàn)無TGC跳轉(zhuǎn)配置的CAS登陸URL

Cas server端登陸后http請求過程
1. post提交用戶信息驗(yàn)證:
http request:
Post?https://passport.jzt.com/login?service=http://uc.54315.com/casuc

http response:
302 Found
Location:http://uc.54315.com/casuc?ticket=ST-1-0kdGxVoshSZz2Bp6kMaA-cas01.example.org
Response返回302指示重定向。同時可見response返回兩個cookie: CASPRIVACY=和CASTGC=TGT-1-MRebCegmlpucavmxcPqCUMVc496IiJgl06BGyJ736D7c4UPkCw-cas01.example.org
也就是說:cas server端驗(yàn)證通過后產(chǎn)生ST并在location URL后面賦給ticket。此時往客戶端瀏覽器寫入TGC,并且指示瀏覽器重定向到location位置,其正是客戶端應(yīng)用驗(yàn)證ST的路徑。
此步驟產(chǎn)生2個ticket: TGT,ST;產(chǎn)生一個cookie:TGC,此cookie是通過用戶私密信息與TGT加密生成。
2. Cas client驗(yàn)證ST:
http request:
Get ?http://uc.54315.com/casuc?ticket=ST-1-0kdGxVoshSZz2Bp6kMaA-cas01.example.org

此時客戶端應(yīng)用由于受到shiro的保護(hù),request cookie中就不是JSESSIONID而是shiro的SessionId:sid,uuid模式,其與第一步中的sid一致。

http response:
302Found
Location:http://uc.54315.com/myWhListManager;jsessionid=qqwn1wmrsymy47n8udvf7v2s
Response返回302指示重定向到另一個頁面(第一次訪問的頁面或者shiro配置的successful url),同時可見生成了新的session和sessionID。同時可見response返回2個cookie:? JSESSIONID,為servlet容器產(chǎn)生的session id,其為location中的jsessionid;rememberMe,為shiro為自動登錄配置的。
此步驟驗(yàn)證ST后(通過url connection去cas server驗(yàn)證ST)如果通過則重定向到新頁面(第一次訪問的頁面或者shiro配置的successful url)產(chǎn)生一個新的容器session id。(為何要重新創(chuàng)建session,因?yàn)槠鋾谛碌膕ession中保存登陸了客戶端應(yīng)用的憑證CAS Assertion,其為客戶端驗(yàn)證ST后返回的)到了這步驟以后屬于客戶端自身的邏輯。CAS作用到此為止。
3. 客戶端應(yīng)用頁面

客戶端應(yīng)用A再次訪問
http request:

http response:
200 OK
可以看到這次直接就訪問了,也沒有經(jīng)過驗(yàn)證ticket和與cas服務(wù)端交互。此是因?yàn)閟ession中已經(jīng)保存了cas assertion,所以算作登陸了。
客戶端應(yīng)用B訪問
1. 訪問B應(yīng)用首頁
http request:

http response:
302 Found
Location:?https://passport.jzt.com/login?service=http://localhost:8080/casuc
可見產(chǎn)生了新的shiro session,并提示跳轉(zhuǎn)CAS服務(wù)端登陸URL。
2. 訪問CAS服務(wù)器登陸URL
http request:
Get ?https://passport.jzt.com/login?service=http://localhost:8080/casuc

http response:
302 Found
Location:?http://localhost:8080/casuc?ticket=ST-2-wtWpPg2Sv4d00fXecLSI-cas01.example.org
可見并沒有要求登陸而是直接就提示跳轉(zhuǎn)到location的URL做驗(yàn)證并產(chǎn)生了一個新的ST。這是因?yàn)镃AS服務(wù)端讀取了A應(yīng)用登陸后在瀏覽器生成的TGC, request cookie中帶入了(下圖可以看到),從而認(rèn)為用戶已經(jīng)登陸,所以直接生成ST,并要求重定向到客戶端應(yīng)用B去驗(yàn)證。


3. 驗(yàn)證ST
http request:
Get ?http://localhost:8080/casuc?ticket=ST-2-wtWpPg2Sv4d00fXecLSI-cas01.example.org
http response:
302 Found
Location:?http://localhost:8080/;jsessionid=1jh99lja6wzxw1jweg8ss40yt8
步驟同A應(yīng)用。
4. 訪問B應(yīng)用首頁
如圖

客戶端應(yīng)用A退出
如下圖:

可見登出時發(fā)生四次請求。
1. 第一次請求:
http request:
GET ?https://passport.jzt.com/logout?service=http://uc.54315.com:80/logout
http response:
302 Found
Location:?http://uc.54315.com:80/logout
直接訪問CAS server端的登出url。Cookie中有CASTGC和server端的JSESSIONID。
返回中CASTGC清空,CASPRIVACY清空。 此時說明server端已經(jīng)清除了A應(yīng)用的ST和瀏覽器的CASTGC
2. 第二次請求:

http request:
Get ?http://uc.54315.com/logout
http response:
302 Found
Location:?http://uc.54315.com/
跳轉(zhuǎn)到了客戶端應(yīng)用,發(fā)現(xiàn)新創(chuàng)建了shiro session(sid)和servlet容器session(JSESSIONID)
并且發(fā)現(xiàn)rememberMe和SID的cookie都被換成deleteMe啦。 此為shiro的loginout攔截器干的好事。

3. 第三次請求:
http request:
http response:
302 Found
Location: https://passport.jzt.com/login?service=http://uc.54315.com/casuc
正常訪問首頁,但是因?yàn)闆]登陸所以提示要重定向到CAS服務(wù)端去登陸。(如果有了首頁就改為跳轉(zhuǎn)到首頁)
4. 第四次請求
同原來步驟。
Cas總結(jié)
總的來說,cas(非代理模式,默認(rèn)驗(yàn)證邏輯)是用一個cookie(TGC), N個session(N個子系統(tǒng)session,其中存儲了cas receipt)來保證各應(yīng)用的統(tǒng)一登錄。