首先,这是一个已知的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 向该应用发出退出请求没有负载到用户登录的实例上,用户没有成功退出。