登出直接请求的passport(负责登录,登出管理的系统)
https://passport.qbao.com/cas/logout?service=http://user.qbao.com/usercenter/logout/logout.html
如果登出之前需要先做点什么,可以先请求别的URL,然后重新跳转到passport 登出
比如在登出之前,需要先执行IM的登出
商家平台的登出,要先执行IM登出(销毁IM为商家小二分配的聊天资源),然后才是user的登出 exitUrl: "http://enterprise.qbao.com/merchantUser/webchat/kickOff.html" exitFunc: function(){ $.ajax({ url: ajaxUrl.exitUrl, type: "GET", dataType: "jsonp", jsonp: 'jsonpCallback', success: function(data) { if(data.success) { location.href = "https://passport.qbao.com/cas/logout?service=http://user.qbao.com/usercenter/logout/logout.html"; } else { headerEvent.errortip(data.message); location.href = "https://passport.qbao.com/cas/logout?service=http://user.qbao.com/usercenter/logout/logout.html"; } }, error: function() { headerEvent.errortip("请求错误!"); location.href = "https://passport.qbao.com/cas/logout?service=http://user.qbao.com/usercenter/logout/logout.html"; } }); enterprise的后台逻辑 /** * 退出 */ @RequestMapping(value="/kickOff", produces = "text/html;charset=UTF-8") @ResponseBody public String kickOff(@RequestParam("jsonpCallback") String jsonpCallback) { try { long userId = getOperatorUserId(); String result = HttpClientUtil.sendGetRequest(imApi + "/waiter/" + userId + "/kickoff?appid=" + appid + "&token=" + token +"&WAITER_ID=" + userId, "utf-8"); if(!result.contains("\"code\": 200")){ log.error(">>>>>>>>>>>>调用IM kickoff接口失败,返回结果:" + result); return jsonpCallback + "(" + JSON.toJSONString(AjaxResult.failed("调用IM接口失败")) + ")"; } return jsonpCallback + "(" + JSON.toJSONString(AjaxResult.success()) + ")"; } catch (Exception e) { LOGGER.error("kickOff failed: " + e.getMessage()); return jsonpCallback + "(" + JSON.toJSONString(AjaxResult.failed("系统异常")) + ")"; } }
----------------
user.qbao.com 的登出做了什么,怎么做的
先看配置
<listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> <listener> <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class> </listener> <listener> <listener-class>com.qbao.sso.SSOSessionListener</listener-class> </listener> <listener> <listener-class>com.qbao.sso.SSOSessionAttributeListener</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>
===================
源码和配置分析
USER
<security:logout logout-url="/usercenter/logout/logout.html" success-handler-ref="customLogoutSuccessHandler" /> <bean id="customLogoutSuccessHandler" class="com.user.web.security.CustomLogoutSuccessHandler"> <property name="redisUtil" ref="redisUtil" /> </bean>
LogoutFilter在执行登出成功后,回调CustomLogoutSuccessHandler
CustomLogoutSuccessHandler返回一个用于全站登出的html给浏览器
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler { private RedisUtil redisUtil; public void setRedisUtil(RedisUtil redisUtil) { this.redisUtil = redisUtil; } @Override public void onLogoutSuccess (HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { if (StringUtils.isBlank(request.getParameter("username"))) { request.getRequestDispatcher("/usercenter/logout/logoutSuccess.html").forward(request, response); return; } String []usernameArr = request.getParameter("username").split(","); String username = usernameArr[0]; if (StringUtils.isBlank(redisUtil.hget("AUTO_LOGOUT_AUTO_LOGIN", username))) { return; } redisUtil.hdel("AUTO_LOGOUT_AUTO_LOGIN", username); /** * 防止恶意自动登陆 */ redisUtil.hset("AUTOLOGIN_FLAG", username, "1"); redisUtil.expire("AUTOLOGIN_FLAG", 300); request.setAttribute("username", username); if (usernameArr.length == 3) { request.setAttribute("backUrl", usernameArr[2]); request.setAttribute("sign", usernameArr[1]); } else { request.setAttribute("sign", usernameArr[1]); } request.getRequestDispatcher("/usercenter/autologout/logoutSuccess.html").forward(request, response); } }
/** * 用户登录/退出 */ @Controller @RequestMapping("/usercenter") public class LogoutController extends BaseController { private Logger LOGGER = LoggerFactory.getLogger(LogoutController.class); @RequestMapping(value = "/autologout/logoutSuccess") public String autoLogoutSuccess() { return "auto.logout.success.page"; } <definition name="auto.logout.success.page" extends="empty.page"> <put-attribute name="title" value="钱宝网—看广告,做任务,赚外快" /> <put-attribute name="body" value="/autoLogoutSuccess.jsp" /> </definition> <%@ page contentType="text/html;charset=UTF-8"%> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <c:set value="${pageContext.request.contextPath}" var="ctx" /> <c:set value="${pageContext.request.contextPath}" var="imageQianbaoPath" /> <c:set value="${pageContext.request.contextPath}" var="staticQianbaoPath" /> <fmt:setBundle basename="cas" var="casties"/> <fmt:setBundle basename="domain" var="domains"/> <script type="text/javascript" src="${staticQianbaoPath}/js/jquery-ui-1.8.13/js/jquery-1.5.1.min.js"></script> <script type="text/javascript" src="${staticQianbaoPath}/js/jquery-cookie-master/jquery.cookie.js"></script> <%@ include file="logoutChild.jsp"%> <script type="text/javascript"> $(document).ready(function() { $.removeCookie('JSESSIONID', { path: '/' }); $.removeCookie('userName', { path: '/' }); if ("${backUrl}" != "") { window.location.href = '<fmt:message key="cas.auto.login.url" bundle="${casties}"/>?username=${username}&sign=${sign}&backUrl=${backUrl}'; } else { window.location.href = '<fmt:message key="cas.auto.login.url" bundle="${casties}"/>?username=${username}&sign=${sign}'; } }); </script> <%@ page contentType="text/html;charset=UTF-8"%> <script type="text/javascript" src="<fmt:message key="user.domain" bundle="${domains}"/>/usercenter/logout/logout.html"></script> <script type="text/javascript" src="<fmt:message key="qianbao.domain" bundle="${domains}"/>/account/logout.html"></script> <script type="text/javascript" src="<fmt:message key="qianghongbao.domain" bundle="${domains}"/>/logout.html"></script> <script type="text/javascript" src="<fmt:message key="thor.domain" bundle="${domains}"/>/auction/logout.html"></script> <script type="text/javascript" src="<fmt:message key="m.order.domain" bundle="${domains}"/>/account/logout.htm"></script> <script type="text/javascript" src="<fmt:message key="baochou.domain" bundle="${domains}"/>/account/logout.html"></script> <script type="text/javascript" src="<fmt:message key="help.domain" bundle="${domains}"/>/account/logout.html"></script> <script type="text/javascript" src="<fmt:message key="goods.domain" bundle="${domains}"/>/goods/logout.html"></script> <script type="text/javascript" src="http://events.qianbao666.com/account/logout.html"></script> <script type="text/javascript" src="<fmt:message key="baoquan.domain" bundle="${domains}"/>/account/logout.html"></script> <script type="text/javascript" src="<fmt:message key="danbao.domain" bundle="${domains}"/>/account/logout.html"></script> <script type="text/javascript" src="http://task.qbao.com/account/logout.html"></script> <script type="text/javascript" src="http://store.qbao.com/account/logout.html"></script> <script type="text/javascript" src="http://sign.qbao.com/account/logout.html"></script> <script type="text/javascript" src="http://charge.qbao.com/charge/logout.html"></script><script type="text/javascript" src="http://vc.qbao.com/account/logout.html"></script>
浏览器收到了user给的应答页面,加载script,在各个子系统执行登出
======================================
enterprise系统
<security:logout logout-url="/account/logout.html" logout-success-url="/account/logoutSuccess.html" /> /** * 用户退出 */ @Controller @RequestMapping("/account") public class AccountController { @RequestMapping(value = "/logoutSuccess") @ResponseBody public String logoutSuccess() { return "success"; } }
charles捕获浏览器返回的报文
==============
oh yeah,我现在不光会SSO登录,还会SSO登出了,yeah,yeah!!!