shiro+cas 单点登出解决

本文主要解决单点登出问题,实现在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的逻辑。


最终解决思路:

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);
    }
    


猜你喜欢

转载自blog.csdn.net/csdn_blog_/article/details/80019127