時間:2017年3月22日星期三
說明:本文部份內容均來自慕課網。@慕課網:http://www.imooc.com
教學示例源碼:無
我的學習源碼:https://github.com/zccodere/s...javascript
課程目標html
認識並理解SSO及其應用,並能根據其實現原理自行實現SSO。
學習內容java
1.SSO的介紹和應用體驗(以新浪爲例) SSO:一次登陸,到處穿梭 2.SSO的分類介紹的實現探討 同域SSO:不一樣的應用位於同一個域名下面 跨域SSO:不一樣的應用位於不一樣的域名下面 3.各類SSO的具體實現介紹的代碼示例
同域SSO圖示jquery
SSO的實現步驟和原理git
以旅遊是購買的通票爲例:github
SSO特色:web
1.必需要登錄一次 2.票據與驗票機制
實現SSO的步驟拆解ajax
關鍵:存儲票據(購票與存儲),查驗票據(是否有票與是否有效)
核心技術點實現原理:spring
比照旅遊進行
教學示例流程圖json
我的學習流程圖
項目搭建
說明:教學使用SSH搭建演示項目,我在學習時使用springboot搭建,源碼能夠在個人github上查看、下載、運行等。由於本節主要是講SSO單點登陸,並非將項目搭建,因此搭建過程省略。
項目命名爲:myssosamedomain
編寫校驗工具類
package com.myimooc.sso.web.util; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; /** * 登陸校驗工具類 * @author ZhangCheng * @date 2017-03-22 * @version V1.0 */ public class LoginCheck { /** 測試用戶名 */ public static final String USERNAME="user"; /** 測試密碼*/ public static final String PASSWORD="123"; /** Cookie鍵 */ public static final String COOKIE_NAME = "ssocookie"; /** Cookie值*/ public static final String COOKIE_VALUE = "sso"; /** * 登陸用戶名和密碼校驗 * @param username 用戶名 * @param password 密碼 * @return true用戶名和密碼正確;false用戶名或密碼錯誤 */ public static boolean checkLogin(String username,String password){ if(USERNAME.equalsIgnoreCase(username) && PASSWORD.equalsIgnoreCase(password)){ return true; } return false; } /** * 校驗Cookie * @param request * @return true正確;false錯誤 */ public static boolean checkCookie(HttpServletRequest request){ Cookie[] cookies = request.getCookies(); if( cookies == null){ return false; } for (Cookie cookie : cookies) { if(COOKIE_NAME.equals(cookie.getName()) && COOKIE_VALUE.equals(cookie.getValue())){ return true; } } return false; } }
編寫校驗控制器
package com.myimooc.sso.web.controller; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.myimooc.sso.web.util.LoginCheck; /** * SSO登陸控制器 * @author ZhangCheng * @date 2017-03-22 * @version V1.0 */ @Controller @RequestMapping("/sso") public class LoginController { /** * 處理用戶登陸請求 * @param username 用戶名 * @param password 密碼 * @param gotoUrl 登陸成功後請求路徑 * @param response * @return */ @PostMapping("/doLogin") public ModelAndView doLogin(String username,String password, String gotoUrl,HttpServletResponse response){ ModelAndView mv = new ModelAndView("login_fail"); // 校驗用戶名和密碼 boolean ok = LoginCheck.checkLogin(username, password); // 判斷是否登陸成功 if(ok){ Cookie cookie = new Cookie(LoginCheck.COOKIE_NAME,LoginCheck.COOKIE_VALUE); // 頂級域名下,全部應用都是可見的 cookie.setPath("/"); // 添加Cookie response.addCookie(cookie); mv.setViewName("redirect:"+gotoUrl); } return mv; } /** * 跳轉到登陸頁面 * @return */ @GetMapping("/login") public ModelAndView login(){ return new ModelAndView("login"); } }
編寫登陸頁面
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登陸</title> </head> <body> <center> <h1>請登陸</h1> <form action="/sso/doLogin" method="post"> <input type="hidden" name="gotoUrl" value="${gotoUrl}"/> <span>用戶名:</span><input type="text" name="username"/> <span>密 碼:</span><input type="password" name="password"/> <input type="submit"> </form> </center> </body> </html>
編寫登陸失敗頁面
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登陸失敗</title> </head> <body> <center> <h1>登陸失敗</h1> <a href="[@common.ctx/]/sso/login">從新登陸</a> </center> </body> </html>
demo1控制器
package com.myimooc.sso.demo1; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.myimooc.sso.web.util.LoginCheck; /** * * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ @Controller public class DemoOneController { @RequestMapping("/demo1") public ModelAndView main(HttpServletRequest request) { ModelAndView mv = new ModelAndView(); if (LoginCheck.checkCookie(request)) { mv.setViewName("demo1"); return mv; } mv.addObject("gotoUrl", "/demo1"); mv.setViewName("login"); return mv; } }
demo2控制器
package com.myimooc.sso.demo2; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.myimooc.sso.web.util.LoginCheck; /** * * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ @Controller public class DemoTwoController { @RequestMapping("/demo2") public ModelAndView main(HttpServletRequest request) { ModelAndView mv = new ModelAndView(); if (LoginCheck.checkCookie(request)) { mv.setViewName("demo2"); return mv; } mv.addObject("gotoUrl", "/demo2"); mv.setViewName("login"); return mv; } }
demo1頁面
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>歡迎訪問demo1</title> </head> <body> <h1>這是demo1的主頁</h1> </body> </html>
demo2頁面
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>歡迎訪問demo2</title> </head> <body> <h1>這是demo2的主頁</h1> </body> </html>
訪問demo1頁面須要登陸
訪問demo2頁面須要登陸
在demo1頁面處登陸
登陸成功,能夠訪問demo1頁面
再次訪問demo2時,不須要登陸便可訪問
教學示例流程圖
我的學習流程圖
經過修改host文件,來模擬實現父子域名。
文件路徑:C:\Windows\System32\drivers\etc\hosts
修改以下
說明:正常狀況下,應該分別創建三個項目,對應demo1.x.com、demo2.x.com、check.x.com。但爲了演示講解方便,咱們經過項目裏面對應的包名來區分是哪一個項目。
項目搭建
項目命名爲:myssosamefather
編寫消息響應類
package com.myimooc.sso.util; import java.io.Serializable; /** * 消息響應對象 * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ public class RespMessage implements Serializable{ private static final long serialVersionUID = 1L; /** 響應編號 */ private String respCode; /** 響應消息 */ private String respMsg; public String getRespCode() { return respCode; } public void setRespCode(String respCode) { this.respCode = respCode; } public String getRespMsg() { return respMsg; } public void setRespMsg(String respMsg) { this.respMsg = respMsg; } }
編寫登陸校驗工具類
package com.myimooc.sso.util; /** * 登陸校驗工具類 * * @author ZhangCheng * @date 2017-03-22 * @version V1.0 */ public class LoginCheck { /** 測試用戶名 */ public static final String USERNAME = "user"; /** 測試密碼 */ public static final String PASSWORD = "123"; /** Cookie鍵 */ public static final String COOKIE_NAME = "ssocookie"; /** Cookie值 */ public static final String COOKIE_VALUE = "sso"; /** * 登陸用戶名和密碼校驗 * * @param username * 用戶名 * @param password * 密碼 * @return true已登陸;false未登陸 */ public static boolean checkLogin(String username, String password) { if (USERNAME.equalsIgnoreCase(username) && PASSWORD.equalsIgnoreCase(password)) { return true; } return false; } /** * 校驗Cookie * @param cookieName * @param cookieValue * @return */ public static boolean checkCookie(String cookieName,String cookieValue) { if (cookieName == null || cookieName=="") { return false; } if (cookieValue == null || cookieValue=="") { return false; } if (COOKIE_NAME.equals(cookieName) && COOKIE_VALUE.equals(cookieValue)) { return true; } return false; } }
編寫http請求工具類
package com.myimooc.sso.util; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import com.alibaba.fastjson.JSONObject; /** * http工具類 * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ public class HttpUtils { /** * 向指定url路徑發起get請求,校驗cookie * @param url 路徑 * @param cookieName * @param cookieValue * @return */ public static RespMessage doGet(String url,String cookieName,String cookieValue){ RespMessage respMessage = new RespMessage(); HttpURLConnection httpURLConnection = null; URL targetUrl = null; try{ targetUrl = new URL(url+"?cookieName="+cookieName+"&cookieValue="+cookieValue); httpURLConnection = (HttpURLConnection) targetUrl.openConnection(); httpURLConnection.setRequestMethod("GET"); httpURLConnection.connect(); InputStream in = httpURLConnection.getInputStream(); InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); StringBuffer sb = new StringBuffer(); String temp = null; while((temp=br.readLine())!=null){ sb.append(temp); } br.close(); isr.close(); in.close(); JSONObject resultJson = JSONObject.parseObject(sb.toString()); respMessage.setRespCode(resultJson.getString("respCode")); respMessage.setRespMsg(resultJson.getString("respMsg")); return respMessage; }catch (Exception e) { respMessage.setRespCode("500"); respMessage.setRespMsg("Cookie校驗請求失敗"); return respMessage; }finally { if(httpURLConnection !=null){ httpURLConnection.disconnect(); } } } }
check.x.com:編寫認證中心控制器
package com.myimooc.sso.check.x.com; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.myimooc.sso.util.LoginCheck; import com.myimooc.sso.util.RespMessage; /** * SSO登陸控制器 * * @author ZhangCheng * @date 2017-03-22 * @version V1.0 */ @Controller @RequestMapping("/sso") public class LoginController { /** * 處理用戶登陸請求 * * @param username * 用戶名 * @param password * 密碼 * @param gotoUrl * 登陸成功後請求路徑 * @param response * @return */ @PostMapping("/doLogin") public ModelAndView doLogin(String username, String password, String gotoUrl, HttpServletResponse response) { ModelAndView mv = new ModelAndView("login_fail"); // 校驗用戶名和密碼 boolean ok = LoginCheck.checkLogin(username, password); // 判斷是否登陸成功 if (ok) { Cookie cookie = new Cookie(LoginCheck.COOKIE_NAME, LoginCheck.COOKIE_VALUE); // 設置在父域下面 cookie.setDomain("x.com"); // 頂級域名下,全部應用都是可見的 cookie.setPath("/"); // 添加Cookie response.addCookie(cookie); mv.setViewName("redirect:" + gotoUrl); } return mv; } /** * 校驗cookie * @param cookieName * @param cookieValue * @param response * @return */ @GetMapping("/checkCookie") @ResponseBody public RespMessage checkCookie(String cookieName,String cookieValue,HttpServletResponse response){ RespMessage result = new RespMessage(); result.setRespCode("500"); result.setRespMsg("CookieName或CookieValue無效"); boolean isOk = LoginCheck.checkCookie(cookieName, cookieValue); if(isOk){ result.setRespCode("200"); result.setRespMsg("Cookie有效"); } return result; } /** * 跳轉到登陸頁面 * * @return */ @GetMapping("/login") public ModelAndView login() { return new ModelAndView("login"); } }
demo1.x.com:編寫demo1項目控制器
package com.myimooc.sso.demo1.x.com; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.myimooc.sso.util.HttpUtils; import com.myimooc.sso.util.RespMessage; /** * * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ @Controller public class DemoOneController { @RequestMapping("/demo1") public ModelAndView main(HttpServletRequest request) { ModelAndView mv = new ModelAndView(); //校驗cookie是否爲空 Cookie[] cookies = request.getCookies(); if(cookies != null && cookies.length > 0){ //校驗cookie是否存在 for(Cookie cookie : cookies){ if("ssocookie".equals(cookie.getName())){ //向校驗服務器發送校驗請求 String url = "http://check.x.com:8080/sso/checkCookie"; RespMessage respMessage = HttpUtils.doGet(url, cookie.getName(), cookie.getValue()); if("200".equals(respMessage.getRespCode())){ mv.setViewName("demo1"); return mv; } } } } mv.addObject("gotoUrl", "http://demo1.x.com:8080/demo1"); mv.setViewName("login"); return mv; } }
demo2.x.com:編寫demo2項目控制器
package com.myimooc.sso.demo2.x.com; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.myimooc.sso.util.HttpUtils; import com.myimooc.sso.util.RespMessage; /** * * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ @Controller public class DemoTwoController { @RequestMapping("/demo2") public ModelAndView main(HttpServletRequest request) { ModelAndView mv = new ModelAndView(); //校驗cookie是否爲空 Cookie[] cookies = request.getCookies(); if(cookies != null && cookies.length > 0){ //校驗cookie是否存在 for(Cookie cookie : cookies){ if("ssocookie".equals(cookie.getName())){ //向校驗服務器發送校驗請求 String url = "http://check.x.com:8080/sso/checkCookie"; RespMessage respMessage = HttpUtils.doGet(url, cookie.getName(), cookie.getValue()); if("200".equals(respMessage.getRespCode())){ mv.setViewName("demo2"); return mv; } } } } mv.addObject("gotoUrl", "http://demo2.x.com:8080/demo2"); mv.setViewName("login"); return mv; } }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <center> <h1>請登陸</h1> <form action="http://check.x.com:8080/sso/doLogin" method="post"> <input type="hidden" name="gotoUrl" value="${gotoUrl}"/> <span>用戶名:</span><input type="text" name="username"/> <span>密 碼:</span><input type="password" name="password"/> <input type="submit"> </form> </center> </body> </html>
請注意觀察瀏覽器URL地址
訪問demo1.x.com:須要登陸
訪問demo2.x.com:須要登陸
在demo1.x.com處登陸成功後,跳轉至demo1頁面
再訪問demo2.x.com的demo2頁面時,再也不須要登陸了
教學示例流程圖
我的學習流程圖
經過修改host文件,來模擬實現跨域應用。
文件路徑:C:\Windows\System32\drivers\etc\hosts
修改以下
說明:正常狀況下,應該分別創建三個項目,對應www.a.com、www.b.com、www.x.com。但爲了演示講解方便,咱們經過項目裏面對應的包名來區分是哪一個項目。
項目搭建
項目命名爲:myssocrossdomain
完成後的目錄結構以下
編寫消息響應類
package com.myimooc.sso.util; import java.io.Serializable; import java.util.Map; /** * 消息響應對象 * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ public class RespMessage implements Serializable{ private static final long serialVersionUID = 1L; /** 響應編號 */ private String respCode; /** 響應消息 */ private String respMsg; /** 響應數據 */ private Map<String,Object> respArgs; public String getRespCode() { return respCode; } public void setRespCode(String respCode) { this.respCode = respCode; } public String getRespMsg() { return respMsg; } public void setRespMsg(String respMsg) { this.respMsg = respMsg; } public Map<String, Object> getRespArgs() { return respArgs; } public void setRespArgs(Map<String, Object> respArgs) { this.respArgs = respArgs; } @Override public String toString() { return "RespMessage [respCode=" + respCode + ", respMsg=" + respMsg + ", respArgs=" + respArgs + "]"; } }
編寫http請求工具類
package com.myimooc.sso.util; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; import com.alibaba.fastjson.JSONObject; /** * Http請求工具類 * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ public class HttpUtils { /** * 向指定url路徑發起get請求 * @param url 請求路徑 * @param param 請求參數 * @return */ public static RespMessage doGet(String url,Map<String,String> param){ RespMessage respMessage = new RespMessage(); HttpURLConnection httpURLConnection = null; URL targetUrl = null; try{ // 拼裝請求參數 StringBuffer targetUrlStr = new StringBuffer(url).append("?"); for(Map.Entry<String, String> entry : param.entrySet()){ targetUrlStr.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); } url = targetUrlStr.substring(0,targetUrlStr.length()-1); targetUrl = new URL(url); httpURLConnection = (HttpURLConnection) targetUrl.openConnection(); httpURLConnection.setRequestMethod("GET"); httpURLConnection.connect(); InputStream in = httpURLConnection.getInputStream(); InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); StringBuffer sb = new StringBuffer(); String temp = null; while((temp=br.readLine())!=null){ sb.append(temp); } br.close(); isr.close(); in.close(); JSONObject resultJson = JSONObject.parseObject(sb.toString()); respMessage.setRespCode(resultJson.getString("respCode")); respMessage.setRespMsg(resultJson.getString("respMsg")); JSONObject resultJsonMap = JSONObject.parseObject(resultJson.getString("respArgs")); respMessage.setRespArgs(resultJsonMap); return respMessage; }catch (Exception e) { respMessage.setRespCode("500"); respMessage.setRespMsg("請求發起失敗"); return respMessage; }finally { if(httpURLConnection !=null){ httpURLConnection.disconnect(); } } } }
www.x.com:編寫認證中心校驗工具類
package com.myimooc.sso.www.x.com; /** * 登陸校驗工具類 * * @author ZhangCheng * @date 2017-03-22 * @version V1.0 */ public class LoginCheck { /** 測試用戶名 */ public static final String USERNAME = "user"; /** 測試密碼 */ public static final String PASSWORD = "123"; /** Cookie鍵 */ public static final String COOKIE_NAME = "ssocookie"; /** Cookie值 */ public static final String COOKIE_VALUE = "sso"; /** * 登陸用戶名和密碼校驗 * * @param username * 用戶名 * @param password * 密碼 * @return true已登陸;false未登陸 */ public static boolean checkLogin(String username, String password) { if (USERNAME.equalsIgnoreCase(username) && PASSWORD.equalsIgnoreCase(password)) { return true; } return false; } /** * 校驗Cookie * @param cookieName * @param cookieValue * @return */ public static boolean checkCookie(String cookieName,String cookieValue) { if (cookieName == null || cookieName=="") { return false; } if (cookieValue == null || cookieValue=="") { return false; } if (COOKIE_NAME.equals(cookieName) && COOKIE_VALUE.equals(cookieValue)) { return true; } return false; } }
www.x.com:編寫認證中心控制器
package com.myimooc.sso.www.x.com; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.myimooc.sso.util.RespMessage; /** * SSO登陸控制器 * * @author ZhangCheng * @date 2017-03-22 * @version V1.0 */ @Controller @RequestMapping("/sso") public class LoginController { /** * 校驗用戶信息 * @param param * @return */ @GetMapping("/doLogin") @ResponseBody public RespMessage doLogin(String username,String password) { RespMessage result = new RespMessage(); result.setRespCode("500"); result.setRespMsg("用戶名或密碼錯誤"); // 校驗用戶名和密碼 boolean ok = LoginCheck.checkLogin(username,password); // 判斷是否登陸成功 if (ok) { result.setRespCode("200"); result.setRespMsg("用戶名和密碼正確"); List<Map<String,String>> targetCookies = new ArrayList<Map<String,String>>(); // 向www.a.com服務器發送增長cookie Map<String,String> targetCookiea = new HashMap<String,String>(); String urla = "http://www.a.com/a/addCookie"; targetCookiea.put("targetUrl", urla); targetCookiea.put("cookieName", LoginCheck.COOKIE_NAME); targetCookiea.put("cookieValue", LoginCheck.COOKIE_VALUE); // 向www.b.com服務器發送增長cookie Map<String,String> targetCookieb = new HashMap<String,String>(); String urlb = "http://www.b.com/b/addCookie"; targetCookieb.put("targetUrl", urlb); targetCookieb.put("cookieName", LoginCheck.COOKIE_NAME); targetCookieb.put("cookieValue", LoginCheck.COOKIE_VALUE); targetCookies.add(targetCookiea); targetCookies.add(targetCookieb); Map<String,Object> args = new HashMap<String,Object>(); args.put("targetCookies", targetCookies); result.setRespArgs(args); } return result; } /** * 校驗cookie * @param cookieName * @param cookieValue * @param response * @return */ @GetMapping("/checkCookie") @ResponseBody public RespMessage checkCookie(String cookieName,String cookieValue){ RespMessage result = new RespMessage(); result.setRespCode("500"); result.setRespMsg("CookieName或CookieValue無效"); boolean isOk = LoginCheck.checkCookie(cookieName, cookieValue); if(isOk){ result.setRespCode("200"); result.setRespMsg("Cookie有效"); } return result; } }
www.x.com:編寫登陸頁
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登陸</title> <script type="text/javascript" src="[@common.ctx /]/static/plugin/jquery/jquery.min.js"></script> <script type="text/javascript" src="[@common.ctx /]/static/plugin/jquery/jquery.cookie.js"></script> <script type="text/javascript" src="[@common.ctx /]/static/script/login.js"></script> </head> <body> <center> <h1>請登陸</h1> <form> <input type="hidden" id="ctx" value="${contextPath}" /> <input id="gotoUrl_input" type="hidden" name="gotoUrl" value="${gotoUrl}"/> <span>用戶名:</span><input id="username_input" type="text" name="username"/> <span>密 碼:</span><input id="password_input" type="password" name="password"/> <input id="login_button" type="button" value="登陸"> </form> </center> </body> </html>
www.x.com:編寫login.js
/** * 登陸js */ $(function(){ var ctx = $("#ctx").val(); $("#login_button").click(function(){ login(); }); }); function login(){ // 獲取登陸信息 var username=$("#username_input").val(); var password=$("#password_input").val(); var path=$("#path_input").val(); var gotoUrl=$("#gotoUrl_input").val(); var requesturl="/a/doLogin"; $.ajax({ type:"POST", async:false,//發送同步請求 url:requesturl, data:"username="+username+"&password="+password, success:function(result){ // 登陸失敗 if(result.respCode != 200 ){ alert(result.respMsg); return; } // 登陸成功 var targetCookies = result.respArgs.targetCookies; // 向服務器發出添加cookie請求 $.each(targetCookies,function(i,targetCookie){ var targetUrl = targetCookie.targetUrl; var cookieName = targetCookie.cookieName; var cookieValue = targetCookie.cookieValue; creat(targetUrl,cookieName,cookieValue); }); } }); // 跳轉到目標頁 window.location.href=gotoUrl; } /** js利用iframe實現跨域添加cookie */ function creat(targetUrl,cookieName,cookieValue){ var iframe = document.createElement('iframe'); var targetSrc = targetUrl+"?"+"cookieName="+cookieName+"&cookieValue="+cookieValue; iframe.src=targetSrc; document.body.appendChild(iframe); }
www.a.com:編寫控制器
package com.myimooc.sso.www.a.com; import java.util.HashMap; import java.util.Map; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.myimooc.sso.util.RespMessage; import com.myimooc.sso.util.HttpUtils; /** * * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ @Controller @RequestMapping("/a") public class DemoOneController { /** * 跳轉到demo1的主頁 * @param request * @return */ @RequestMapping("/demo1") public ModelAndView demo1(HttpServletRequest request) { ModelAndView mv = new ModelAndView(); //校驗cookie是否爲空 Cookie[] cookies = request.getCookies(); if(cookies != null && cookies.length > 0){ //校驗cookie是否存在 for(Cookie cookie : cookies){ if("ssocookie".equals(cookie.getName())){ // 封裝請求參數 Map<String,String> param = new HashMap<String,String>(); param.put("cookieName", cookie.getName()); param.put("cookieValue", cookie.getValue()); // 向校驗服務器發送校驗請求 String url = "http://www.x.com/sso/checkCookie"; RespMessage respMessage = HttpUtils.doGet(url, param); // 校驗經過 if("200".equals(respMessage.getRespCode())){ mv.setViewName("demo1"); return mv; } } } } // 登陸失敗從新登陸 String path = request.getContextPath(); mv.addObject("contextPath",path); mv.addObject("path","a"); mv.addObject("gotoUrl", "http://www.a.com/a/demo1"); mv.setViewName("login"); return mv; } /** * 用戶登陸 * @param param * @return */ @PostMapping(value="/doLogin") @ResponseBody public RespMessage doLogin(@RequestParam Map<String,String> param){ // 向校驗服務器發送校驗請求 String url = "http://www.x.com/sso/doLogin"; RespMessage respMessage = HttpUtils.doGet(url, param); System.out.println("SSO服務器響應消息:"+respMessage); return respMessage; } /** * 想當前域添加cookie * @param cookieName * @param cookieValue * @param response */ @RequestMapping(value="/addCookie") public void addCookie(String cookieName,String cookieValue,HttpServletResponse response){ Cookie cookie = new Cookie(cookieName,cookieValue); cookie.setPath("/"); response.addCookie(cookie); } }
www.b.com:編寫控制器
package com.myimooc.sso.www.b.com; import java.util.HashMap; import java.util.Map; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.myimooc.sso.util.HttpUtils; import com.myimooc.sso.util.RespMessage; /** * * @author ZhangCheng * @date 2017-04-02 * @version V1.0 */ @Controller @RequestMapping("/b") public class DemoTwoController { @RequestMapping("/demo2") public ModelAndView main(HttpServletRequest request) { ModelAndView mv = new ModelAndView(); //校驗cookie是否爲空 Cookie[] cookies = request.getCookies(); if(cookies != null && cookies.length > 0){ //校驗cookie是否存在 for(Cookie cookie : cookies){ if("ssocookie".equals(cookie.getName())){ // 封裝請求參數 Map<String,String> param = new HashMap<String,String>(); param.put("cookieName", cookie.getName()); param.put("cookieValue", cookie.getValue()); // 向校驗服務器發送校驗請求 String url = "http://www.x.com/sso/checkCookie"; RespMessage respMessage = HttpUtils.doGet(url, param); // 校驗經過 if("200".equals(respMessage.getRespCode())){ mv.setViewName("demo2"); return mv; } } } } // 登陸失敗從新登陸 mv.addObject("contextPath",request.getContextPath()); mv.addObject("path","b"); mv.addObject("gotoUrl", "http://www.b.com/b/demo2"); mv.setViewName("login"); return mv; } /** * 用戶登陸 * @param param * @return */ @PostMapping(value="/doLogin") @ResponseBody public RespMessage doLogin(@RequestParam Map<String,String> param){ // 向校驗服務器發送校驗請求 String url = "http://www.x.com/sso/doLogin"; RespMessage respMessage = HttpUtils.doGet(url, param); System.out.println("SSO服務器響應消息:"+respMessage); return respMessage; } /** * 向當前域添加cookie * @param cookieName * @param cookieValue * @param response */ @RequestMapping(value="/addCookie") public void addCookie(String cookieName,String cookieValue,HttpServletResponse response){ Cookie cookie = new Cookie(cookieName,cookieValue); cookie.setPath("/"); response.addCookie(cookie); } }
注意觀察瀏覽器URL地址
訪問www.a.com的a項目須要登陸
訪問www.b.com的b項目須要登陸
在www.a.com域登陸
登陸成功
www.b.com域便可直接訪問,免登錄
1.核心是COOKIE,須要注意設置的域、位置和安全性
注意COOKIE的加密
2.應用羣的安全性問題:木桶效應
即應用羣的安全性受限於某個安全性最低的應用