前言:今天刚学完B站up主“楠哥教你学Java”前些日子的一个直播教学,经过录播跟着把代码敲了一遍,整理了一下。前半部分取自楠哥的笔记,后部分代码和思惟导图本身概括总结,代码细节今天是撸不完了,明后天在多研究几遍一些细节css
单点登陆
什么是单点登陆:一处登陆,到处登陆,一处登出,到处登出。html
用户只须要登陆一次就能够访问全部相互信任的应用系统。前端
SSO
Single Sign On 单点登陆java
企业业务整合解决方案程序员
一票通web
SSO 原理
- 当用户第一次访问淘宝的时候,由于尚未登陆,会被引导到认证中心进行登陆。
- 根据用户提供的登陆信息,认证系统进行身份验证,若是经过,则登陆成功,并返回给用户一个认证的凭据(token)。
- 当用户访问天猫时,就会将这个 token 带上,做为本身认证的凭据。
- 应用系统接收到请求后会把 token 送到认证中心进行校验,检查 token 的合法性。
- 若是经过校验,用户就能够在不用再次登陆的状况下访问天猫了。
SSO 实现技术
Cookie 单点登陆spring
使用 Cookie 做为媒介,存放用户凭证。数据库
用户登陆淘宝以后,返回一个 token,存入客户端的 Cookie 中,当用户访问天猫的时候,会自动带上 Cookie,这样 token 又传给了认证中心,进行校验。浏览器
分布式 Session前端框架
一、用户第一次登陆时,将会话信息,写入分布式 Session。
二、用户再次登陆时,获取分布式 Session,判断是否有登陆信息,若是没有则返回登陆页面。
三、Session 通常存储到 Redis 中,由于它有持久化功能,若是分布式 Session 宕机后,重启以后能够从持久化存储中从新加载会话信息。
SSO 常见方案
OAuth2(第三方登陆受权)
第三方系统访问主系统资源,用户无需将主系统的帐户告知第三方,只须要经过主系统的受权,第三方就可使用主系统的资源。
jwt
Json Web Token,是为了在网络应用之间传递信息而执行的一种,基于 JSON 的开放标准,难度较高,须要了解不少协议,偏向底层的东西,须要你基于 JWT 认证协议,本身开放 SSO 服务和权限控制。
CAS(不是并发的 CAS)
单点登陆的 CAS 和并发的 CAS 彻底是两码事
中央认证服务,Central Authentication Service
CAS 是耶鲁大学发起的一个开源项目,为 Web 应用系统提供单点登陆的解决方案,实现多个系统只须要登陆一次,无需重复登陆。
- CAS Server
- CAS Client
Server 和 Client 分别独立部署,Server 主要负责认证工做
Client 负责处理对客户端资源的访问请求,须要登陆时,重定向到 Server 进行认证。
一、受权服务器保存一个全局 session,多个客户端各自保存本身的 session。
二、客户端登陆时判断本身的 session 是否已经登陆,若是没有登陆,则重定向到服务器进行受权(带上本身的地址,用于回调)。
三、受权服务器判断全局的 session 是否已经登陆,若是未登陆则重定向到登陆页面,提供用户登陆,登陆成功以后,受权服务器重定向到客户端,带上 ticket。
四、客户端收到 ticket 后,请求服务器获取用户信息。
五、服务器赞成客户端受权后,服务器保存用户信息到全局 session,客户端将用户信息保存至本地 session。
手写单点登陆系统架构
Spring Boot + Thymelaf
Thymeleaf 是个什么?
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 相似的模板引擎,它能够彻底替代 JSP 。相较与其余的模板引擎,它有以下三个极吸引人的特色:
1.Thymeleaf 在有网络和无网络的环境下皆可运行,即它可让美工在浏览器查看页面的静态效果,也可让程序员在服务器查看带数据的动态页面效果。这是因为它支持 html 原型,而后在 html 标签里增长额外的属性来达到模板+数据的展现方式。浏览器解释 html 时会忽略未定义的标签属性,因此 thymeleaf 的模板能够静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
2.Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,能够直接套用模板实现JSTL、 OGNL表达式效果,避免天天套模板、该jstl、改标签的困扰。同时开发人员也能够扩展和建立自定义的方言。
3.Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,能够快速的实现表单绑定、属性编辑器、国际化等功能。
SSO(主工程) 建立三个子工程
- taobao (客户端)
- tmall (客户端)
- server (服务端)
SSO_Client_Taobao
一、首先配置淘宝客户端的配置文件application.yml(访问端口、thymeleaf 模板、先后缀、标头、编码)
server: port: 8081 spring: thymeleaf: suffix: .html prefix: classpath:/templates/ servlet: content-type: text/html encoding: UTF-8
二、resources下建立templates目录,写入index.html静态页面
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" th:href="@{/layui/css/layui.css}" media="all"> </head> <body> <div class="layui-container" style="width: 700px;height: 600px;margin-top: 0px;padding-top: 60px;"> <h1>淘宝首页</h1> <div style="margin-left: 460px; width: 200px;"> 欢迎回来!admin <a th:href="${serverLogoutUrl}"> <button class="layui-btn layui-btn-warm layui-btn-radius">退出</button> </a> </div> <img width="700px" th:src="@{/images/taobao.png}"> </div> </body> </html>
三、static目录导入layui,layui是一个前端框架
static目录导入一个图片模拟淘宝首页
四、建立运行类TaobaoApplication
package com.janeroad; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class TaobaoApplication { public static void main(String[] args) { SpringApplication.run(TaobaoApplication.class,args); } }
五、建立控制器 TaobaoHandler,处理异步请求
package com.janeroad.controller; import com.janeroad.util.SSOClientUtil; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpSession; [@Controller](https://my.oschina.net/u/1774615) public class TaobaoHandler { @GetMapping("/taobao") public String index(Model model){ model.addAttribute("serverLogoutUrl", SSOClientUtil.getServerLogoutUrl()); return "index"; } @RequestMapping("/logout") public String logout(HttpSession session){ session.invalidate(); return "redirect:/taobao"; } }
六、建立拦截器TaobaoInterceptor,继承与HandelerInterceptor,用于当请求服务端页面时判断用户是否登陆,若是登陆过放行,若是未登陆跳转登陆页面
package com.janeroad.interceptor; import com.janeroad.util.HttpUtil; import com.janeroad.util.SSOClientUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.HandlerInterceptor; import org.thymeleaf.util.StringUtils; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.HashMap; @Slf4j public class TaobaoInterceptor implements HandlerInterceptor { /** * 功能描述: <br> * true 放行 * false 不放行 * @Param: [request, response, handler] * @Return: boolean * @Author: JaneRoad * @Date: 2020/3/29 15:30 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //一、判断是否已经登录 HttpSession session =request.getSession(); Boolean isLogin =(Boolean) session.getAttribute("isLogin"); if(isLogin!=null && isLogin){ return true; } //二、判断 token String token=request.getParameter("token"); if(!StringUtils.isEmpty(token)){ //验证token log.info("token存在,须要验证"); //发起验证 String httpUrl = SSOClientUtil.SERVER_HOST_URL+"/verify"; HashMap<String,String> params = new HashMap<>(); params.put("token",token); params.put("clientLogoutUrl",SSOClientUtil.getClientLogoutUrl()); String isVerify = HttpUtil.sendHttpRequest(httpUrl,params); if("true".equals(isVerify)){ log.info("token验证经过,token={}",token); //token保存到本地Cookie Cookie cookie = new Cookie("token",token); response.addCookie(cookie); session.setAttribute("isLogin",true); return true; } } //三、跳转到认证中心进行登陆 SSOClientUtil.redirectToCheckToken(request, response); return false; } }
七、建立工具类SSOClientUtil
package com.janeroad.util; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Properties; public class SSOClientUtil { private static Properties properties = new Properties(); public static String SERVER_HOST_URL; public static String CLIENT_HOST_URL; static { try { properties.load(SSOClientUtil.class.getClassLoader().getResourceAsStream("sso.properties")); SERVER_HOST_URL = properties.getProperty("server.host.url"); CLIENT_HOST_URL = properties.getProperty("client.host.url"); } catch (IOException e) { e.printStackTrace(); } } //跳转到认证中心 public static void redirectToCheckToken(HttpServletRequest request, HttpServletResponse response){ StringBuffer url=new StringBuffer(); url.append(SERVER_HOST_URL) .append("/checkToken?redirectUrl=") .append(CLIENT_HOST_URL) .append(request.getServletPath()); try { response.sendRedirect(url.toString()); } catch (IOException e) { e.printStackTrace(); } } public static String getServerLogoutUrl(){ return SERVER_HOST_URL+"/logout"; } public static String getClientLogoutUrl(){ return CLIENT_HOST_URL+"/logout"; } }
八、resources下写入一个配置文件sso.properties,用于记录服务端地址
server.host.url=http://localhost:8080 client.host.url=http://localhost:8081
九、建立工具类HttpUtil
package com.janeroad.util; import org.springframework.util.StreamUtils; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.util.Map; public class HttpUtil { /** * id=1 * name=tom * {id=1,name=tom} id=1&name=tom * @param httpUrl * @param params * @return */ public static String sendHttpRequest(String httpUrl, Map<String,String> params){ try { URL url = new URL(httpUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); if(params!=null && params.size()>0){ StringBuffer stringBuffer = new StringBuffer(); for(Map.Entry<String,String> entry:params.entrySet()){ stringBuffer.append("&") .append(entry.getKey()) .append("=") .append(entry.getValue()); } connection.getOutputStream().write(stringBuffer.substring(1).toString().getBytes("UTF-8")); } connection.connect(); String response = StreamUtils.copyToString(connection.getInputStream(), Charset.forName("UTF-8")); return response; } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } return null; } }
SSO_Server
一、首先配置服务端的配置文件application.yml(访问端口、thymeleaf 模板、先后缀、标头、编码)
server: port: 8080 spring: thymeleaf: prefix: classpath:/templates/ suffix: .html servlet: content-type: text/html encoding: UTF-8
二、resources下建立templates目录,写入index.html静态页面
<!DOCTYPE html> <html lang="en"> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/layui/css/layui.css" media="all"> </head> <body> <div class="layui-container" style="width: 500px;height: 330px;margin-top: 130px;border: 1px solid #009688;padding-top: 60px;border-radius: 15px"> <form class="layui-form" action="/login" method="post"> <input type="hidden" name="redirectUrl" th:value="${redirectUrl}"> <div class="layui-form-item"> <label class="layui-form-label">用户名</label> <div class="layui-inline"> <input type="text" name="username" lay-verify="username" autocomplete="off" placeholder="请输入用户名" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">密码</label> <div class="layui-inline"> <input type="password" name="password" lay-verify="password" placeholder="请输入密码" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-form-item"> <button class="layui-btn" lay-submit="" lay-filter="demo2" style="margin-left: 160px;">登录</button> </div> </form> </div> <script src="/layui/layui.js" charset="utf-8"></script> <script> layui.use(['form'], function(){ var form = layui.form; //自定义验证规则 form.verify({ username: function(value){ if(value.length == 0){ return '用户名不能为空'; } } ,password: [/(.+){6,12}$/, '密码必须6到12位'] }); }); </script> </body> </html>
三、同客户端,static目录导入layui,layui是一个前端框架
四、建立运行类ServerApplication
package com.janeroad; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ServerApplication { public static void main(String[] args) { SpringApplication.run(ServerApplication.class,args); } }
五、建立控制器 ServerHandler,处理异步请求
package com.janeroad.controller; import com.janeroad.db.MockDB; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.thymeleaf.util.StringUtils; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.util.HashSet; import java.util.Set; import java.util.UUID; @Controller @Slf4j public class ServerHandler { /** * 功能描述: 第一次登陆验证 * 〈〉 * @Param: [redirectUrl, session, model] * @Return: java.lang.String * @Author: JaneRoad * @Date: 2020/3/29 16:21 */ @RequestMapping("/checkToken") public String checkToken(String redirectUrl, HttpSession session, Model model, HttpServletRequest request) { //获取token String token = (String) session.getServletContext().getAttribute("token"); if(StringUtils.isEmpty(token)){ model.addAttribute("redirectUrl",redirectUrl); return "login"; }else{ //验证token Cookie[] cookies = request.getCookies(); for (Cookie cookie : cookies) { if(cookie.getValue().equals(token)){ //验证经过,返回客户端 log.info("token验证经过"); return "redirect:"+redirectUrl+"?token="+token; } } } model.addAttribute("redirectUrl",redirectUrl); return "login"; } @PostMapping("/login") public String login(String username, String password, String redirectUrl, HttpSession session, Model model){ //判断登陆 if("admin".equals(username) && "123123".equals(password)){ //一、建立token String token = UUID.randomUUID().toString(); log.info("token建立成功!token={}",token); //二、token保存到全局会话中 session.getServletContext().setAttribute("token",token); //三、token保存到数据库 MockDB.tokenSet.add(token); //四、返回客户端 return "redirect:"+redirectUrl+"?token="+token; }else{ log.error("用户名密码错误!username={},password={}",username,password); model.addAttribute("redirectUrl",redirectUrl); return "login"; } } @RequestMapping("/verify") @ResponseBody public String verifyToken(String token,String clientLogoutUrl){ if(MockDB.tokenSet.contains(token)){ Set<String> set = MockDB.clientLogoutUrlMap.get(token); if(set == null){ set = new HashSet<>(); } set.add(clientLogoutUrl); MockDB.clientLogoutUrlMap.put(token,set); return "true"; } return "false"; } @RequestMapping("/logout") public String logout(HttpSession session){ session.invalidate(); return "login"; } }
六、建立监听器,登出的时候帐号销毁的时候须要操做
package com.janeroad.listener; import com.janeroad.db.MockDB; import com.janeroad.util.HttpUtil; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import java.util.Iterator; import java.util.Set; @WebListener public class SessionListener implements HttpSessionListener { @Override public void sessionDestroyed(HttpSessionEvent se) { //一、删除全局会话中的token //二、删除数据库的用户信息 //三、通知全部客户端销毁session String token = (String) se.getSession().getServletContext().getAttribute("token"); se.getSession().getServletContext().removeAttribute("token"); MockDB.tokenSet.remove(token); Set<String> set = MockDB.clientLogoutUrlMap.get(token); Iterator<String> iterator = set.iterator(); while(iterator.hasNext()){ HttpUtil.sendHttpRequest(iterator.next(),null); } MockDB.clientLogoutUrlMap.remove(token); } }
七、建立监听器配置ListenerConfig
package com.janeroad.config; import com.janeroad.listener.SessionListener; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class ListenerConfig implements WebMvcConfigurer { @Bean public ServletListenerRegistrationBean bean(){ ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean(); bean.setListener(new SessionListener()); return bean; } }
八、建立MockDB模拟数据库
package com.janeroad.db; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class MockDB{ //记录token public static Set<String> tokenSet=new HashSet<>(); //客户端登出地址 public static Map<String,Set<String>> clientLogoutUrlMap = new HashMap<>(); }
九、建立HttpUtil工具类
package com.janeroad.util; import org.springframework.util.StreamUtils; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.util.Map; public class HttpUtil { /** * id=1 * name=tom * {id=1,name=tom} id=1&name=tom * @param httpUrl * @param params * @return */ public static String sendHttpRequest(String httpUrl, Map<String,String> params){ try { URL url = new URL(httpUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); if(params!=null && params.size()>0){ StringBuffer stringBuffer = new StringBuffer(); for(Map.Entry<String,String> entry:params.entrySet()){ stringBuffer.append("&") .append(entry.getKey()) .append("=") .append(entry.getValue()); } connection.getOutputStream().write(stringBuffer.substring(1).toString().getBytes("UTF-8")); } connection.connect(); String response = StreamUtils.copyToString(connection.getInputStream(), Charset.forName("UTF-8")); return response; } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } return null; } }
SSO_Client——Tmall
天猫客户端和淘宝的类似
一、首先配置淘宝客户端的配置文件application.yml(访问端口、thymeleaf 模板、先后缀、标头、编码)
server: port: 8082 spring: thymeleaf: prefix: classpath:/templates/ suffix: .html servlet: content-type: text/html encoding: UTF-8
二、resources下建立templates目录,写入index.html静态页面
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" th:href="@{/layui/css/layui.css}" media="all"> </head> <body> <div class="layui-container" style="width: 700px;height: 600px;margin-top: 0px;padding-top: 60px;"> <h1>天猫首页</h1> <div style="margin-left: 460px; width: 200px;"> 欢迎回来!admin <a th:href="${serverLogoutUrl}"> <button class="layui-btn layui-btn-warm layui-btn-radius">退出</button> </a> </div> <img width="700px" th:src="@{/images/tmall.png}"> </div> </body> </html>
三、static目录导入layui,layui是一个前端框架。image下导入图片,模拟天猫首页
四、建立运行类TmallApplication
package com.janeroad; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class TmallApplication { public static void main(String[] args) { SpringApplication.run(TmallApplication.class,args); } }
五、建立控制器 TmallHandler,处理异步请求
package com.janeroad.controller; import com.janeroad.util.SSOClientUtil; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpSession; @Controller public class TmallHandler { @GetMapping("/tmall") public String index(Model model){ model.addAttribute("serverLogoutUrl", SSOClientUtil.getServerLogoutUrl()); return "index"; } @RequestMapping("/logout") public String logout(HttpSession session){ session.invalidate(); return "redirect:/tmall"; } }
六、建立拦截器TmallInterceptor,继承与HandelerInterceptor,用于当请求服务端页面时判断用户是否登陆,若是登陆过放行,若是未登陆跳转登陆页面
package com.janeroad.interceptor; import com.janeroad.util.HttpUtil; import com.janeroad.util.SSOClientUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.HashMap; @Slf4j public class TmallInterceptor implements HandlerInterceptor { /** * true 放行 * false 不放行 * * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //一、判断是否已经登陆 HttpSession session = request.getSession(); Boolean isLogin = (Boolean) session.getAttribute("isLogin"); if (isLogin != null && isLogin) { return true; } //二、判断token String token = request.getParameter("token"); if (!StringUtils.isEmpty(token)) { //验证token log.info("token存在,须要验证"); //发起验证 String httpUrl = SSOClientUtil.SERVER_HOST_URL + "/verify"; HashMap<String, String> params = new HashMap<>(); params.put("token", token); params.put("clientLogoutUrl",SSOClientUtil.getClientLogoutUrl()); String isVerify = HttpUtil.sendHttpRequest(httpUrl, params); if ("true".equals(isVerify)) { log.info("token验证经过,token={}", token); //token保存到本地Cookie Cookie cookie = new Cookie("token", token); response.addCookie(cookie); session.setAttribute("isLogin", true); return true; } } //三、跳转到认证中心进行登陆 SSOClientUtil.redirectToCheckToken(request, response); return false; } }
七、建立工具类SSOClientUtil
package com.janeroad.util; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Properties; public class SSOClientUtil { private static Properties properties = new Properties(); public static String SERVER_HOST_URL; public static String CLIENT_HOST_URL; static { try { properties.load(SSOClientUtil.class.getClassLoader().getResourceAsStream("sso.properties")); SERVER_HOST_URL = properties.getProperty("server.host.url"); CLIENT_HOST_URL = properties.getProperty("client.host.url"); } catch (IOException e) { e.printStackTrace(); } } //跳转到认证中心 public static void redirectToCheckToken(HttpServletRequest request, HttpServletResponse response) { StringBuffer url = new StringBuffer(); url.append(SERVER_HOST_URL) .append("/checkToken?redirectUrl=") .append(CLIENT_HOST_URL) .append(request.getServletPath()); try { response.sendRedirect(url.toString()); } catch (IOException e) { e.printStackTrace(); } } public static String getServerLogoutUrl(){ return SERVER_HOST_URL+"/logout"; } public static String getClientLogoutUrl(){ return CLIENT_HOST_URL+"/logout"; } }
建立工具类HttpUtil
package com.janeroad.util; import org.springframework.util.StreamUtils; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.util.Map; public class HttpUtil { /** * id=1 * name=tom * {id=1,name=tom} id=1&name=tom * @param httpUrl * @param params * @return */ public static String sendHttpRequest(String httpUrl, Map<String,String> params){ try { URL url = new URL(httpUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); if(params!=null && params.size()>0){ StringBuffer stringBuffer = new StringBuffer(); for(Map.Entry<String,String> entry:params.entrySet()){ stringBuffer.append("&") .append(entry.getKey()) .append("=") .append(entry.getValue()); } connection.getOutputStream().write(stringBuffer.substring(1).toString().getBytes("UTF-8")); } connection.connect(); String response = StreamUtils.copyToString(connection.getInputStream(), Charset.forName("UTF-8")); return response; } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } return null; } }
八、resources下写入一个配置文件sso.properties,用于记录服务端地址
server.host.url=http://localhost:8080 client.host.url=http://localhost:8082
最终实现效果
访问localhost://8081/taobao,模拟访问淘宝跳转到登陆页面
访问localhost://8082/tmall,模拟访问天猫跳转到登陆页面
淘宝输入用户名密码,跳转淘宝首页
刷新localhost://8082/tmall,天猫自动登陆进入首页
在天猫和淘宝任一界面退出帐号,另外一个界面随之退出,从而实现一处登陆到处登陆,一处登出到处登出。