本文主要解决单点登出问题,实现在A应用退出后,共享同一个CAS TGT票据的B应用也被退出
退出流程:
1、A应用退出时,请求cas服务端,销毁服务端票据
2、cas服务端向单点注册的B应用发送退出请求
3、B应用收到请求后,退出
单点登出官方解决方案:
在web.xml中配置对应的监听器和过滤即可
<!-- 单点登出监听器 --> <listener> <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class> </listener> <!-- 单点登出 --> <filter> <filter-name>CAS Single Sign Out Filter</filter-name> <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class> </filter> <filter-mapping> <filter-name>CAS Single Sign Out Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
但是官方解决方案只是对标准的http session进行处理,如果项目中使用了Shiro Session进行管理的话,官方解决方案无法实现单点登出效果。需要自行实现收到CAS服务器发过来的logout请求时,自行处理销毁Shiro Session的逻辑。
最终解决思路:
扫描二维码关注公众号,回复:
39337 查看本文章
1 、首先记录CAS Token, 在登录后CAS Server回调时进行。将Token和session id绑定起来(用HashMap)。
/** * Associates a token request with the current HTTP session by recording the mapping * in the the configured {@link SessionMappingStorage} container. * * @param request HTTP request containing an authentication token. */ public void recordSession(final HttpServletRequest request) { final HttpSession session = request.getSession(this.eagerlyCreateSessions); if (session == null) { logger.debug("No session currently exists (and none created). Cannot record session information for single sign out."); return; } final String token = CommonUtils.safeGetParameter(request, this.artifactParameterName); logger.debug("Recording session for token {}", token); try { this.sessionMappingStorage.removeBySessionById(session.getId()); } catch (final Exception e) { // ignore if the session is already marked as invalid. Nothing we can do! } sessionMappingStorage.addSessionById(token, session); }
2、 然后收到CAS Server发过来的登出请求(请求中带有token)时,根据token从HashMap中取得session id,将session id做一个清理标记(如:session.setAttribute("isLogout", true))。
这时候不能直接进行登出处理,因为拥有logout方法的Shiro Subject对象是和线程绑定的,所以这里不能获取到正确的Subject对象。
3、 用户再次使用网站时,这时候检查用户的session id是不是已被标记为清理,如果已被标记,此时掉用Subject对象的logout方法,进行登出处理。
Subject subject = SecurityUtils.getSubject(); Session session = subject.getSession(false); if (session!=null&&session.getAttribute("isLogout")!=null && (boolean)session.getAttribute("isLogout")) { try { subject.logout(); } catch (SessionException ise) { logger.debug("Encountered session exception during logout. This can generally safely be ignored.", ise); }