ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

绝对完全跨域统一单点登录登出

绝对完全跨域统一单点登录登出 应用场景:多个系统下同属于一个用户,当用户登录了web1系统,那么访问web2,web3. . . . æ—¶å€™ï¼Œç”¨æˆ·å°±æ— éœ€å†æ¬¡ç™»å½•ã€‚å¦‚ï¼šæ·˜å®ä¸Žå¤©çŒ«ï¼Œç™»å‡ºä¹Ÿå¦‚æ­¤ï¼Œä¸€ä¸ªç³»ç»Ÿç™»å‡ºï¼Œå ¶ä»–ç³»ç»Ÿçš„ç™»å½•ä¹Ÿéšä¹‹å¤±æ•ˆï¼Œè¿™å°±æ˜¯ç»Ÿä¸€å•ç‚¹ç™»å½•ç™»å‡ºã€‚è¿™é‡Œé ç½®ä¸‰ä¸ªwebç³»ç»Ÿï¼Œä¸€ä¸ªç”¨æˆ·ä¸­å¿ƒç³»ç»Ÿä¸ºæ —å­ã€‚é ç½®hosts实现跨域:127.0.0.1 ssofront.ljtest.xxxx.com #用户中心127.0.0.1 my.kuaiji.com #web1127.0.0.1 my.zikao.com #web2127.0.0.1 my.xuelxuew.com #web3nginx é ç½®ç”¨äºŽç»Ÿä¸€ç™»å½•é¡µé¢è½¬å‘server {listen 80;server_name ssofront.ljtest.xxxx.com;location /ajax/ {proxy_pass http://ssofront.ljtest.xxxx.com:9092/;}location / {root D:/Java/projects/SSO_Single;index index.html;}}å ˆçœ‹çœ‹æ•ˆæžœå›¾ï¼šç»Ÿä¸€ç™»å½•é¡µé¢ï¼šæ‰€æœ‰çš„web系统登录都重定向到用户中心的统一登录页面统一登录之后访问各系统当web1点击登录重定向到用户中心统一登录之后,再访问web2,web3系统都已经是登录状态了。能够实现这种效果就说明用户中心,3个web系统都分别在自己的域名下成功的把token放到各自的cookie下了,而且4个系统都是跨域的,所以cookieåœ¨è¿™å››ä¸ªç³»ç»Ÿé—´æ˜¯ä¸å¯å ±äº«çš„ï¼Œæ‰€ä»¥å·²ç»è¾¾åˆ°è·¨åŸŸç»Ÿä¸€ç™»å½•äº†ã€‚å¦‚ä½•å®žçŽ°çš„ï¼Ÿï¼Ÿæˆ‘ä»¬å ˆçœ‹çœ‹æµç¨‹å›¾å„ä½çœ‹å®˜å¦‚æžœçœ‹å®Œæµç¨‹å›¾è¿˜ä¸æ˜¯å¾ˆæ¸ æ™°ï¼Œä¸”å¬æˆ‘åˆ†æžï¼šå½“æˆ‘ä»¬ç¬¬ä¸€æ¬¡è®¿é—®web1ç³»ç»Ÿæ—¶ï¼ˆæœªç™»å½•çŠ¶æ€ï¼Œå ¶ä»–web系统也未登录过),此时经过过滤器,token,action当然为null,就会查找cookie是否存在token,不过是否取得都把这个tokenæ‹¿åˆ°ç”¨æˆ·ä¸­å¿ƒåŽ»æ ¡éªŒï¼Œç¬¬ä¸€æ¬¡è‚¯å®šæ‹¿ä¸åˆ°ï¼Œæ‰€ä»¥æ ¡éªŒå¤±è´¥ï¼Œefftoken有效token为空,重定向到用户中心(重定向由浏览器重新发出可以获取到用户中心的cookie)获取cookie中的token,token去到SSOæ ¡éªŒæ˜¯å¦å¤±æ•ˆï¼Œç¬¬ä¸€æ¬¡è®¿é—®æ‰€ä»¥token为空失效,返回token,重定向回web1系统(此时得带上参数:返回的token 和 actioncallback(ç”¨ä»¥æ ‡è¯†æ˜¯ç”¨æˆ·ä¸­å¿ƒé‡å®šå‘å›žæ¥çš„ï¼Œé¿å å¤šæ¬¡é‡å®šå‘)),到这里就完成了一次询问,假如一直未登录,每次访问web1系统都会去用户中心询问是否有别的系统登录过啊,有就返回有效tokenæ”¾å ¥web1系统的session和cookie中,那么下次访问就拿着这个tokenåŽ»ç”¨æˆ·ä¸­å¿ƒæ ¡éªŒåˆ¤æ–­æ˜¯å¦å¤±æ•ˆã€‚å½“æˆ‘ä»¬åŽ»åˆ°ç”¨æˆ·ä¸­å¿ƒç™»å½•äº†ç”Ÿæˆtoken,tokenä¼šæ”¾å ¥ç”¨æˆ·ä¸­å¿ƒçš„cookie中,然后重定向回web1系统,经过过滤器时执行上述步骤便可以拿到用户中心的有效tokenã€‚å ¶ä¸­ä»»ä½•ä¸€ä¸ªç³»ç»Ÿç™»å‡ºéƒ½ä¼šè°ƒç”¨ç”¨æˆ·ä¸­å¿ƒå•ç‚¹ç™»å‡ºï¼Œæ­¤æ—¶tokenå¤±æ•ˆï¼Œå ¶ä»–ç³»ç»Ÿå†æ¬¡è®¿é—®æ—¶å°±ä¼šå†æ¬¡è¯¢é—®æ˜¯å¦å¤±æ•ˆï¼Œå¤±æ•ˆæ¸ ç©ºcookieï¼Œè¿™æ ·å°±å®Œæˆç»Ÿä¸€ç™»å‡ºå•¦ã€‚å ¶ä»–ç³»ç»ŸåŒç†ä¹Ÿæ˜¯å¦‚æ­¤ã€‚è¿™ä¹ˆè¿˜å­˜åœ¨ä¸€ä¸ªå°é—®é¢˜å°±æ˜¯å½“ä»Žç”¨æˆ·ä¸­å¿ƒè¯¢é—®å‘çŽ°æ²¡æœ‰ç™»å½•è¿‡ï¼Œå¸¦å‚æ•°é‡å®šå‘å›žweb1系统,浏览器上的urlä¼šåŠ ä¸Šå‚æ•° ?tokenactioncallbackï¼Œå½“æˆ‘ä»¬åªæ˜¯åˆ·æ–°é¡µé¢æ²¡æœ‰å ¶ä»–æ“ä½œï¼Œæ­¤æ—¶è¿‡æ»¤å™¨ä¸­action值为callback会跳过到用户中心的询问,而tokenæ˜¯å¤±æ•ˆçš„æœªç™»å½•çŠ¶æ€ï¼Œæ‰€ä»¥çš„ç‚¹å‡»é¡µé¢åˆ·æ–°ï¼Œè¿™ä¸ªé—®é¢˜å¤§å®¶å¦‚æžœæƒ³çš„å¥½çš„è§£å†³åŠžæ³•å¯ä»¥å‘Šè¯‰æˆ‘ä¸€ä¸‹ã€‚ä¸»è¦ä»£ç ï¼šweb系统:Login.javaRequestMapping(/login)public void login(HttpServletRequest request, HttpServletResponse response){try {//获取上一个URL地址String previousUrl request.getHeader(Referer).toString();response.sendRedirect(LOGIN_URLpreviousUrl);}catch (IOException e) {e.printStackTrace();}}统一登录过滤器public class UnifiedLoginFilter extends OncePerRequestFilter {Value(${tokenExpired.url})private String TOKENEXPIRED_URL;Value(${userCenterToken.url})private String USERCENTERTOKEN_URL;private final static String ACTION_NAME callback;Autowiredprivate UserService userService;Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {String action ServletRequestUtils.getStringParameter(request, action, null);HttpSession session request.getSession();String currentUrl request.getRequestURL().toString();//获取用户中心有效tokenString effectiveToken null;String currentToken null;boolean doFilter true;if(ACTION_NAME.equals(action)) {effectiveToken ServletRequestUtils.getStringParameter(request, token, null);} else {currentToken (String) session.getAttribute(SystemConfig.SESSION_TOKEN_KEY);Cookie[] cookies request.getCookies();if (StringUtils.isBlank(currentToken) cookies ! null) {for (int i 0; i cookies.length; i) {Cookie cookie cookies[i];if (cookie ! null SystemConfig.COOKIE_TOKEN_NAME.equals(cookie.getName())) {currentToken cookie.getValue();break;}}}String result HttpUtil.doGet4Json(TOKENEXPIRED_URLcurrentToken);if(StringUtils.isNotBlank(result)) {JSONObject object JSONObject.parseObject(result);effectiveToken object.getString(data);if(StringUtils.isBlank(effectiveToken)) {doFilter false;response.sendRedirect(USERCENTERTOKEN_URLcurrentUrl);}}}if(doFilter) {//用户中心token有效if(StringUtils.isNotBlank(effectiveToken)) {if(effectiveToken.equals(currentToken)) {//当前系统token有效,把tokenå­˜å ¥sessionsession.setAttribute(SystemConfig.SESSION_TOKEN_KEY, effectiveToken);} else {//当前系统token失效,更新tokensetCookie(effectiveToken, request, response);}}//用户中心token失效else {removeCookie(request, response);}//重定向去掉url地址参数if(ACTION_NAME.equals(action) StringUtils.isNotBlank(effectiveToken)) {response.sendRedirect(currentUrl);} else {filterChain.doFilter(request, response);}}}}è¿‡æ»¤å™¨é ç½®web.xmlunifiedLoginFilterorg.springframework.web.filter.DelegatingFilterProxyunifiedLoginFilter/*使用DelegatingFilterProxy代理过滤器,可以让Springç®¡ç†è¢«ä»£ç†çš„è¿‡æ»¤å™¨ï¼Œè¿™æ ·å°±å¯ä»¥åœ¨è¿‡æ»¤å™¨ä¸­è®¿é—®Spring容器中的bean,属性等。用户中心:tokenæ ¡éªŒ UserInfo.javaApiOperation(value 重定向获取用户中心Token)ApiImplicitParam(name redirectUrl, value 回调地址, required true, dataType String, paramType query)RequestMapping(value /userCenterToken, method RequestMethod.GET)public void userCenterToken(HttpServletRequest request, HttpServletResponse response) {String redirectUrl ServletRequestUtils.getStringParameter(request, redirectUrl, null);String schoolId this.getSchoolId(request);String token null;Cookie[] cookies request.getCookies();if(null ! cookies) {for (int i 0; i cookies.length; i) {Cookie cookie cookies[i];if (cookie ! null config.getCookieTokenName().equals(cookie.getName())) {token cookie.getValue();break;}}}try {String effectiveToken getEffectiveToken(token,schoolId);response.sendRedirect(redirectUrl?tokeneffectiveTokenactioncallback);} catch (Exception e) {TRACER.error(, e);e.printStackTrace();}}ApiOperation(value æ ¡éªŒToken是否失效)ApiImplicitParam(name token, value 用户 Token, required true, dataType String, paramType query)RequestMapping(value /tokenExpired, method RequestMethod.GET)ResponseBodypublic ResponseEntity tokenExpired(HttpServletRequest request, HttpServletResponse response) {try {String token ServletRequestUtils.getStringParameter(request, token, null);String schoolId this.getSchoolId(request);String effectiveToken getEffectiveToken(token,schoolId);return this.success(effectiveToken);} catch (Throwable t) {TRACER.error(, t);return this.fail(TransactionStatus.INTERNAL_SERVER_ERROR);}}private String getEffectiveToken(String token, String schoolId) throws Exception {String effectiveToken ;HashMap map new HashMap(1);map.put(token, token);HttpPlainResult result httpConnManager.invoke(HttpMethod.GET, config.getSsoHost()/inner/tokenExpired, map,schoolId);TRACER.info(result.getResult());HttpResultDetail entry HttpResultHandler.handle(result, TokenStatus.class);if (entry.isOK()) {TokenStatus tokenStatus entry.getResult();if (!tokenStatus.getExpired()) {effectiveToken token;}}return effectiveToken;}统一登录 Login.javaHttpPlainResult result httpConnManager.invoke(HttpMethod.POST, config.getSsoHost() “/inner/login”, map, schoolId);TRACER.info(result.getResult());HttpResultDetail entry ‍‍HttpResultHandler.handle(result,Token.class);if(entry.isOK()){ClientTypeEnum clientTypeEnum ClientTypeEnum.convertString2ClientType(clientType);if(clientTypeEnum ClientTypeEnum.WEB){String token entry.getResult().getToken();Cookie token_cookie new Cookie(config.getCookieTokenName(),token);token_cookie.setMaxAge(config.getCookieTokenTimeout());token_cookie.setDomain(request.getHeader(Host).split(:)[0]);response.addCookie(token_cookie);return this.success(redirectUrl,token_cookie);}else{return this.success(entry.getResult(), entry.getResponseStatus());}}else if(entry.isClientError()){return this.error(entry.getResponseMessage(), entry.getResponseStatus());}else if(entry.isServerError()){return th‍‍is.fail(entry.getResponseMessage(), entry.getResponseStatus());}统一登出 Logout.javaHttpPlainResult result httpConnManager.invoke(HttpMethod.POST, config.getSsoHost()”/inner/logout”, map,schoolId);TRACER.info(result.getResult());HttpResultDetail entry HttpResultHandler.handle(result,String.class);if(entry.isOK()){Cookie token_cookie new Cookie(config.getCookieTokenName(),null);token_cookie.setMaxAge(0);token_cookie.setDomain(request.getHeader(“Host”).split(“:”)[0]);response.addCookie(token_cookie);return this.success(entry.getResult(), entry.getResponseStatus());}else if(entry.isClientError()){return this.error(entry.getResponseMessage(), entry.getResponseStatus());}else if(entry.isServerError()){return this.fail(entry.getResponseMessage(), entry.getResponseStatus());}作者molashaonian
返回列表