在前面我們講解了CAS的單點登錄客戶端接入,對於CAS的登錄有了更清楚的瞭解,今天我們講解一下在CAS中的單點退出問題。
首先我們要明白單點退出(單點註銷)與註銷的區別:
其實官方文檔也給我們詳細的解釋了:
註銷:
應用程序註銷 - 結束單個應用程序會話
CAS註銷 - 結束CAS SSO會話
請注意,在簡單的情況下,每種情況下的註銷操作對另一種情況都沒有影響。
而單點註銷(SLO):
當CAS配置爲SLO時,它會嘗試向SSO會話期間請求對CAS進行身份驗證的每個應用程序發送註銷消息。CAS旨在支持單點註銷:這意味着除了自己的SSO會話之外,它還能夠使客戶端應用程序會話無效。
對應CAS單點退出的流程原理可以查看CAS單點登錄(一)——初識SSO當時在文章中也有講解。
同樣的我們再來分析一下具體的流程:
- 用戶向系統1發起註銷請求
- 系統1根據用戶與系統1建立的會話id拿到令牌,向SSO認證中心發起註銷請求
- SSO認證中心校驗令牌有效,銷燬全局會話,同時取出所有用此令牌註冊的系統地址
- SSO認證中心向所有註冊系統發起註銷請求
- 各註冊系統接收SSO認證中心的註銷請求,銷燬局部會話
- SSO認證中心引導用戶至登錄頁面
第5條中就詳細分析了,當多個系統接入到CAS中時,單點退出時各註冊系統接收SSO認證中心的註銷請求,銷燬局部會話。
默認CAS單點退出(單點註銷)是開啓的,我們可以手動配置關閉或啓用。
##
# Single Logout配置
#
cas.slo.disabled=false
cas.slo.asynchronous=true
CAS單點註銷主要支持下面兩種方式:
1、Back Channel
CAS服務端直接向各服務客戶端發送HTTP POST消息。這是向服務執行通知的傳統方式。
2、Front Channel
CAS 通過一個異步的AJAX方式的GET請求,通過JSONP去驗證各客戶端服務,來使得各客戶端的session無效。
注意:該方式不一定適用所有客戶端,必須要確保客戶端支持該方式。
CAS單點註銷請求默認是在後臺通過logoutType的屬性配置好了的,默認爲LogoutType.BACK_CHANNEL。
單個服務配置單點註銷:
使用CAS註冊的應用程序可以選擇通過服務管理組件單獨控制單個註銷行爲。服務註冊表中的每個註冊服務都將包含描述如何提交註銷請求的配置。此行爲通過logoutType屬性進行控制,該屬性允許指定是應通過後/前通道提交註銷請求還是爲此應用程序關閉註銷請求。
{
"@class" : "org.apereo.cas.services.RegexRegisteredService",
"serviceId" : "^(https|imaps|http)://.*",
"name" : "web",
"id" : 10000001,
"evaluationOrder" : 10,
"accessStrategy" : {
"@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy",
"enabled" : true,
"ssoEnabled" : true
},
"attributeReleasePolicy": {
"@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy"
},
"theme": "anumbrella",
"logoutType" : "BACK_CHANNEL"
}
註銷請求的請求路徑配置,我們可以爲每個服務配置請求路徑,這樣實現了更大的靈活性。
{
"@class" : "org.apereo.cas.services.RegexRegisteredService",
"serviceId" : "^(https|imaps|http)://.*",
"name" : "web",
"id" : 10000001,
"evaluationOrder" : 10,
"accessStrategy" : {
"@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy",
"enabled" : true,
"ssoEnabled" : true
},
"attributeReleasePolicy": {
"@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy"
},
"theme": "anumbrella",
"logoutType" : "BACK_CHANNEL",
"logoutUrl" : "https://client.anumbrella.net/logout"
}
我們依然使用前面的client-demo來講解CAS單點註銷,注意:在CAS3.2.x版本退出加上service參數,不會自動跳轉,需要在application.properties中配置一下。
##
# Logout配置
#
cas.logout.followServiceRedirects=true
我們client-demo的控制器中添加service參數測試:
@GetMapping("/logout")
public String logout(HttpSession session){
session.removeAttribute(WebSecurityConfig.SESSION_KEY);
return "redirect:https://sso.anumbrella.net:8443/cas/logout?service=https://client.anumbrella.net:9443/";
}
當我們主動退出後,自動跳轉到登錄頁面。
我們啓動一個CAS客戶端服務cas-management,在裏面可以查看到CAS退出的相關配置。
這裏我們將logoutUrl設置爲http://172.16.67.230:8000/logout
,具體地址爲我本機調試IP,通過MAC終端調試工具 nc netcat來監聽端口8000,服務端發送給我們的被動退出請求,方法爲POST。
sudo nc -l 0.0.0.0 8000
當然還可以使用Wireshark來捕獲服務端發送給我們請求,注意:Wireshark抓取數據包的時候發現只能抓取別的機器上的數據包,如果是本機的服務則發現好像抓不到。需要進行一定的配置才行,所以這裏我使用的是nc netcat 工具。
目前我們啓動了兩個客戶端,一個服務端。我們點擊client-demo註銷。
在服務端日誌中我們發現,發送了2次請求。
在命令端我們接收到服務端的POST請求。
然後我們便可以根據logoutRequst請求的參數中去銷燬各個服務端的session,一般情況是session的鍵值對,鍵爲st票據,拿到鍵我們就能刪除具體的session。當然不同的客戶端接入情況不一樣,具體看保存session時是如何做的。
比如上面的logoutRequst的數據形式如下:我們拿到的就是ST。
<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="LR-20-gJ8SYdbM4Ycm-xG3Dve-p3qA" Version="2.0" IssueInstant="2019-04-07T15:40:02Z">
<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">@NOT_USED@</saml:NameID>
<samlp:SessionIndex>ST-21-qK6bcCxu4iJZBBGtG0MtsNsgJ40anumbrelladeiMac</samlp:SessionIndex>
</samlp:LogoutRequest>
這裏我只是簡單演示了一下退出服務端發送的請求,如果我們CAS系統接入很多客戶端,具體客戶端在不同的地址,我們就可以配置自己相應的logoutUrl,然後在被動退出時在POST監聽地址中銷燬掉session即可。
代碼實例:Chapter10