前言:今天剛學完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,天貓自動登陸進入首頁
在天貓和淘寶任一界面退出帳號,另外一個界面隨之退出,從而實現一處登陸到處登陸,一處登出到處登出。