读书人

CAS总结之单点退出篇(CAS到底有没有实

发布时间: 2012-10-24 14:15:58 作者: rapoo

【原创】CAS总结之单点退出篇(CAS到底有没有实现单点退出?)

?


???????????????????????????????????????????????? CAS logout功能的序列图

public synchronized boolean logOutOfService(final String sessionIdentifier) { if (this.loggedOutAlready) { return true; } LOG.debug("Sending logout request for: " + getId()); final String logoutRequest = "<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\"" + GENERATOR.getNewTicketId("LR") + "\" Version=\"2.0\" IssueInstant=\"" + SamlUtils.getCurrentDateAndTime() + "\"><saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">@NOT_USED@</saml:NameID><samlp:SessionIndex>" + sessionIdentifier + "</samlp:SessionIndex></samlp:LogoutRequest>"; this.loggedOutAlready = true; if (this.httpClient != null) { return this.httpClient.sendMessageToEndPoint(getOriginalUrl(), logoutRequest); } return false; }

?

?

public boolean sendMessageToEndPoint(final String url, final String message) { HttpURLConnection connection = null; BufferedReader in = null; try { if (log.isDebugEnabled()) { log.debug("Attempting to access " + url); } final URL logoutUrl = new URL(url); final String output = "logoutRequest=" + URLEncoder.encode(message, "UTF-8"); connection = (HttpURLConnection) logoutUrl.openConnection(); connection.setDoInput(true); connection.setDoOutput(true); connection.setReadTimeout(this.readTimeout); connection.setConnectTimeout(this.connectionTimeout); connection.setRequestProperty("Content-Length", "" + Integer.toString(output.getBytes().length)); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); final DataOutputStream printout = new DataOutputStream(connection .getOutputStream()); printout.writeBytes(output); printout.flush(); printout.close(); in = new BufferedReader(new InputStreamReader(connection .getInputStream())); while (in.readLine() != null) { // nothing to do } if (log.isDebugEnabled()) { log.debug("Finished sending message to" + url); } return true; } catch (final Exception e) { log.error(e,e); return false; } finally { if (in != null) { try { in.close(); } catch (final IOException e) { // can't do anything } } if (connection != null) { connection.disconnect(); } } }

?

?

public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; if ("POST".equals(request.getMethod())) { final String logoutRequest = CommonUtils.safeGetParameter(request, "logoutRequest"); if (CommonUtils.isNotBlank(logoutRequest)) { if (log.isTraceEnabled()) { log.trace ("Logout request=[" + logoutRequest + "]"); } final String sessionIdentifier = XmlUtils.getTextForElement(logoutRequest, "SessionIndex"); if (CommonUtils.isNotBlank(sessionIdentifier)) { final HttpSession session = SESSION_MAPPING_STORAGE.removeSessionByMappingId(sessionIdentifier); if (session != null) { String sessionID = session.getId(); if (log.isDebugEnabled()) { log.debug ("Invalidating session [" + sessionID + "] for ST [" + sessionIdentifier + "]"); } try { session.invalidate(); } catch (final IllegalStateException e) { log.debug(e,e); } } return; } } } else { final String artifact = CommonUtils.safeGetParameter(request, this.artifactParameterName); final HttpSession session = request.getSession(false); if (session != null) { if (log.isDebugEnabled()) { log.debug("Storing session identifier for " + session.getId()); } if (CommonUtils.isNotBlank(artifact)) { try { SESSION_MAPPING_STORAGE.removeBySessionById(session.getId()); } catch (final Exception e) { // ignore if the session is already marked as invalid. Nothing we can do! } SESSION_MAPPING_STORAGE.addSessionById(artifact, session); } } else { log.debug("No Session Found, so ignoring."); } } filterChain.doFilter(servletRequest, servletResponse);}?

public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; final String logoutRequest = CommonUtils.safeGetParameter(request, "logoutRequest"); Enumeration ff = request.getParameterNames(); String a = request.getQueryString(); if (CommonUtils.isNotBlank(logoutRequest)) { final String sessionIdentifier = XmlUtils.getTextForElement(logoutRequest, "SessionIndex"); if (CommonUtils.isNotBlank(sessionIdentifier)) { final HttpSession session = SESSION_MAPPING_STORAGE.removeSessionByMappingId(sessionIdentifier); if (session != null) { String sessionID = session.getId(); try { session.invalidate(); } catch (final IllegalStateException e) { } } } } else{ final String artifact = CommonUtils.safeGetParameter(request, this.artifactParameterName); final HttpSession session = request.getSession(false); if (CommonUtils.isNotBlank(artifact) && session!=null) { try { SESSION_MAPPING_STORAGE.removeBySessionById(session.getId()); } catch (final Exception e) { } SESSION_MAPPING_STORAGE.addSessionById(artifact, session); } } filterChain.doFilter(servletRequest, servletResponse); }

?

URL logoutUrl = new URL(url); String output = (new StringBuilder()).append("logoutRequest=").append(URLEncoder.encode(message, "UTF-8")).toString(); connection = (HttpURLConnection)logoutUrl.openConnection(); connection.setDoInput(true); connection.setDoOutput(true); connection.setRequestMethod("POST"); connection.setReadTimeout(readTimeout); connection.setConnectTimeout(connectionTimeout); connection.setRequestProperty("Content-Length", Integer.toString(output.getBytes().length)); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); DataOutputStream printout = new DataOutputStream(connection.getOutputStream()); printout.writeBytes(output); printout.flush(); printout.close(); 9 楼 JasonMing 2010-06-21 zhenkm0507 写道非常感谢kevindurant关注!!不过在我的实现里面,SingleSignOutFilter 放在最后也是可以的,前提是做过更改。没必要说顺序都搞错了,ok?

默认配置是sign out的放在最前面的,因为这样就可以避免被Authentication Filter拦截了。

不过我用了一个笨方法。。。
自己写了个filter,当访问项目的/logout地址的时候直接清除Cookie和Session。

不过这样项目多了就郁闷了。。。

还是期待CAS4吧,我在他们的SVN上看到应该差不多完成了。 10 楼 JasonMing 2010-06-21 对了,还有你的图(CAS logout 功能的序列图)无效了~~~补个图吧~~~我觉得有图会舒服一点~~~ 11 楼 waitingmyself 2010-10-22 cas-client-core-3.1.10.jar 客户端断点发现发过来的确实是post方式 12 楼 castte 2011-11-11 遇到了一样的问题,在自己的logout方法中增加了:getHttpSession().removeAttribute(org.jasig.cas.client.util.AbstractCasFilter.CONST_CAS_ASSERTION);

可以实现单点登出 13 楼 张小宇 2012-02-10 碰到了类似问题,按照你说的方法改了下,仍然存在问题,是不是修改的地方不止doFilter方法呢? 14 楼 张小宇 2012-02-10 castte 写道遇到了一样的问题,在自己的logout方法中增加了:getHttpSession().removeAttribute(org.jasig.cas.client.util.AbstractCasFilter.CONST_CAS_ASSERTION);

可以实现单点登出

是在DoFilter方法中加入这句话么? 能具体点么? 15 楼 tiger121987 2012-05-11 cas的client应用是集群,现在遇到也实现不了单点退出,如果把集群的服务器撤下只剩一台,单点退出又可以,多台就不行。有什么好的办法解决吗,不管是tomcat集群还是was集群都一样。 16 楼 sodarfish 2012-06-18

tiger121987 写道cas的client应用是集群,现在遇到也实现不了单点退出,如果把集群的服务器撤下只剩一台,单点退出又可以,多台就不行。有什么好的办法解决吗,不管是tomcat集群还是was集群都一样。

一个简单的方法: 各应用提供一个url ,访问这个url就会把当前域下 cookie 都设置过期,并把当前session 失效掉。

这样cas只需要生成一个页面,页面中分别get请求各个系统的这个url就可以了,可以生成多个iframe并指定其src 来实现。

这方法和cas的机制没多大关系,比较简单,而且在业务系统有集群的情况下也可以工作良好。

读书人网 >软件架构设计

热点推荐