shiro cas 单点登录 两个cas client,一个登出另外一个没登出

问题表现:两个站点使用同一个cas单点登录,登录后,在A系统登出,B系统也同时登;而在B系统登出A系统未登出;

问题原因:A系统没有实现cas的logout逻辑。需要实现logoutFilter逻辑;在请求cas.example.com/cas/logout时,Cas Server会将客户端携带的TGT删除,同时回调该TGT对应的所有service;所以cas client需要实现登出逻辑,使会话失效;

参考:http://elim.iteye.com/blog/2144265

 

-----------------------------------------------我来分隔-----------------------------------------------------

一开始并不知道这套逻辑;只从表现出来的差异去查找。

表现:在A系统登出,再去刷新B系统页面;会得到一个新的JSESSIONID, 也就是服务端把当前连接当成新的会话;

查找JSESSIONID的生成代码。一开始想到应该是tomcat生成的,所以根据http://stackoverflow.com/questions/595872/under-what-conditions-is-a-jsessionid-created;提供的说法,在调用request.getSession()或request.getSession(true)时触发是否生成JSESSIONID(根据请求头是否带有JSESSIONID的cookie);其中找到:

JSESSIONID这个字符串值定义在: tomcat-embed-core.jar下的org.apache.catalina.util.SessionConfig类下的一个常量属性;

把JSESSIONID植入cookie的是 org.apache.catalina.connector.Request类的doGetSession方法;

如果使用了Shiro,shiro会拦截以上步骤,覆盖为自己的实现;

shiro中也默认是JSESSIONID,定义在org.apache.shiro.web.servlet.ShiroHttpSession类下的属性;

session生成是org.apache.shiro.web.session.mgt.DefaultSessionManager类的create方法;

cookie的生成是在org.apache.shiro.web.session.mgt.DefaultSessionManager类的storeSessionId方法;

shiro的seesionId默认使用的是UUID.randomUUID()方法;

shiro会在认证失败(会先获取当前session,并判断是否已认证)的拦截器的onAccessDenied()方法中调用saveRequestAndRedirectToLogin(...).保存当前请求到新session.并且跳转到cas登录页

-------------------------------------------下面是logoutFilter的实现逻辑----------------------------------

   /**
     * 拦截所有请求
     * --如果请求中包含了ticket参数(成功登陆cas后,cas server会自动跳转到cas client并在url中带上ticket),
     *   记录ticket和sessionID的映射
     *
     * --如果请求中包含logoutRequest参数(说明是cas logout, cas server回调ticket相同的所有cas client),
     *   标记session为无效 如果session不为空,且被标记为无效,则登出
     *
     * @param request  the incoming ServletRequest
     * @param response the outgoing ServletResponse
     * @return 是logoutRequest请求返回false,否则返回true
     * @throws Exception if there is any error.
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest req = (HttpServletRequest) request;
        if (handler.isTokenRequest(req)) {
            // 是否是登陆成功的回调。请求链接中含有ticket参数,记录ticket和sessionID
            handler.recordSession(req);
            return true;
        } else if (handler.isLogoutRequest(req)) {
            // cas服务器发送的请求,链接中含有logoutRequest参数,在之前记录的session中设置logoutRequest属性为true
            // 因为Subject是和线程是绑定的,所以无法获取登录的Subject直接logout
            handler.invalidateSession(req);
            // Do not continue up filter chain
            return false;
        } else {
            logger.trace("Ignoring URI " + req.getRequestURI());
        }
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession(false);
        if (session != null && session.getAttribute(handler.getLogoutParameterName()) != null) {
            //如果session存在,且属性中有logoutRequest值,则登出
            try {
                subject.logout();
            } catch (SessionException ise) {
                logger.debug("Encountered session exception during logout.  This can generally safely be ignored.",
                        ise);
            }
        }
        return true;
    }

 

转载于:https://my.oschina.net/u/782865/blog/802982

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
登录(Single Sign-On,简称SSO)是一种身份验证和授权机制,允许用户使用一组凭据(如用户名和密码)登录到多个相关但独立的应用程序或系统中,而无需为每个应用程序独进行身份验证。 在Java中,可以通过使用一些开源框架和技术来实现登录。以下是一个简的示例,展示了如何手动实现基于Cookie的登录: 1. 创建一个登录页面(login.jsp),用于用户输入用户名和密码。 2. 创建一个验证用户的Servlet(LoginServlet),用于验证用户输入的用户名和密码是否正确。 3. 如果验证成功,生成一个唯一的令牌(token)并将其存储在服务器端的缓存或数据库中,并将该令牌作为Cookie发送给客户端。 4. 在其他应用程序中,创建一个过滤器(SSOFilter),用于检查请求中是否存在有效的令牌。 5. 当用户访问其他应用程序时,过滤器会检查请求中的令牌,并验证其有效性。如果令牌有效,则允许用户访问该应用程序;否则,重定向到登录页面进行身份验证。 6. 当用户注销或超时时,删除服务器端存储的令牌,并清除客户端的Cookie。 这只是一个简的示例,实际的登录系统可能涉及更复杂的流程和安全性措施。在实际开发中,建议使用成熟的登录框架,如Spring Security、Shiro等,它们提供了更完善和安全的解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值