首先,這是一個已知的bug。
cas-client通過org.jasig.cas.client.session.SingleSignOutFilter
來實現單點退出。
看看這個主要的類,這裏只摘出我們關注的部分。
public final class SingleSignOutHandler {
/** Mapping of token IDs and session IDs to HTTP sessions */
private SessionMappingStorage sessionMappingStorage = new HashMapBackedSessionMappingStorage();
/**
* Process a request regarding the SLO process: record the session or destroy it.
*
* @param request the incoming HTTP request.
* @param response the HTTP response.
* @return if the request should continue to be processed.
*/
public boolean process(final HttpServletRequest request, final HttpServletResponse response) {
if (isTokenRequest(request)) {
logger.trace("Received a token request");
recordSession(request);
return true;
}
if (isLogoutRequest(request)) {
logger.trace("Received a logout request");
destroySession(request);
return false;
}
logger.trace("Ignoring URI for logout: {}", request.getRequestURI());
return true;
}
可以看到cas-client通過記錄在map的<ticket,sessionId>來管理回話的退出。
原因
很明顯的問題在於,當你有同一個應用多個實例時(即負載均衡),他們之間並不共享 sessionMappingStorage。
現象
這導致了,用戶在其中一個實例中登錄,用戶在別處觸發單點退出,CAS-Server 向該應用發出退出請求沒有負載到用戶登錄的實例上,用戶沒有成功退出。