时间: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.应用群的安全性问题:木桶效应
即应用群的安全性受限于某个安全性最低的应用