SSO 单点登录
来源:互联网 发布:mac桌面图标怎样缩小 编辑:程序博客网 时间:2024/06/06 13:17
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。实现 SSO 的主要工具是 Cookie。
实现步骤
简的来说:申请票据、存储票据、查验票据。
同域 SSO 登录
此处使用 struts2 作为 MVC 框架,可根据实际需要替换
登录界面
接收用户登录信息
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %><!DOCTYPE html><html><head> <meta name="viewport" content="width=device-width, inital-scale=1"> <meta charset="UTF-8"> <title>login</title></head><body> <center> <h1>请登录</h1> <form action="/sso/doLogin.action" method="post"> <span>用户名:</span><input type="text" name="username"> <span>密码 :</span><input type="password" name="password"><br> <%-- gotoUrl 包含从其它页面过来的地址,登录完毕后跳转回 gotoUrl --%> <input type="hidden" name="gotoUrl" value="${gotoUrl}"> <input type="submit"> </form> </center></body></html>
处理用户登录信息
import com.opensymphony.xwork2.ActionSupport;import lee.sso.util.SSOCheck;import org.apache.struts2.ServletActionContext;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletResponse;public class SSOAction extends ActionSupport { private String username; private String password; private String gotoUrl; public String doLogin() { /* 此处不进行数据用户数据验证, 只关注 sso */ boolean ok = SSOCheck.checkLogin(username, password); if (ok) { /* 此处 cookie 值应为加密后的值,此处亦省去 */ Cookie cookie = new Cookie("ssocookie", "sso"); cookie.setPath("/"); HttpServletResponse response = ServletActionContext.getResponse(); response.addCookie(cookie); return SUCCESS; } // 失败此处不做处理,或者返回登录页面 return null; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; }}
处理登录信息工具类
import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;public class SSOCheck { public static final String USERNAME = "user"; public static final String PASSWORD = "123"; public static boolean checkLogin(String username, String password) { return username.equals(USERNAME) && password.equals(PASSWORD) ? true : false; } /** * 实际开发时应放在拦截器,此处为了方便 * * @param request * @return */ public static boolean checkCookie(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); if (cookies != null && cookies.length > 0) { for (Cookie cookie : cookies) { if (cookie.getName().equals("ssocookie") && cookie.getValue() .equals("sso")) return true; } } return false; }}
登录页面的 struts2 配置
<package name="sso" namespace="/sso" extends="struts-default"> <action name="doLogin" class="lee.sso.action.SSOAction" method="doLogin"> <result name="success" type="redirect">${gotoUrl}</result> </action> </package>
编写 domain1
主页,当为用户访问时未登录将先跳转登录页面
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %><!DOCTYPE html><html><head> <meta name="viewport" content="width=device-width, inital-scale=1"> <meta charset="UTF-8"> <title>domain1 的标题</title></head><body> <h1>欢迎访问 domain1,这是 domain1 的主页</h1></body></html>
domain1 Action 类
import com.opensymphony.xwork2.ActionSupport;import lee.sso.util.SSOCheck;import org.apache.struts2.ServletActionContext;import javax.servlet.http.HttpServletRequest;public class Domain1Action extends ActionSupport { private String gotoUrl; public String main() { HttpServletRequest request = ServletActionContext.getRequest(); if (SSOCheck.checkCookie(request)) { return SUCCESS; } // 此处声明登录完成后跳转的页面 gotoUrl = "/domain1/main.action"; return LOGIN; } public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; }}
domain1 的 struts2 配置
<package name="domain1" namespace="/domain1" extends="struts-default"> <action name="main" class="domain1.Domain1Action" method="main"> <result name="success">/domain1.jsp</result> <result name="login">/login.jsp</result> </action> </package>
domain2 与 domain1 区别不大,只需将 1 复制一份,将 1 改为 2 即可。
效果
填写 domain1 (别点提交)
进入 domain2 看看
domain1 点解提交
此时刷新 domain2 登录界面
神奇的一幕发生了,不需要登录信息直接进入 domain2 的主页
这是因为在登录 domain1 后服务器向我们发送了一个 cookie,浏览器保存了。当刷新 domain2 时,浏览器带着未过期的 cookie 给服务器发请求,服务器判断此 cookie 的会话是否还有效,若有,则直接跳过登录页面进入 domain2 主页。
同父域 SSO 登录
若在同一机器部署测试,可更改文件C:\Windows\System32\drivers\etc\hosts
文件
由图可看出,同父域的 SSO 登录与同域 SSO 登录并无多大区别,需要解决的问题有两个,一个是 cookie 的跨域问题以及服务器之间的通信。可根据同域 SSO 登录修改代码。
cookie 跨域
此处主要使用了子域可访问父域cookie
的机制。设置 cookie 时,需要我们统一一个 token
,即 cookie
的变量名。
我们访问http://demo1.x.com/demo1/main.action
时,查看 request.getCookies()
是否包含我们所需的信息,若无,则带着验证后跳转地址<input type="hidden" name="gotoUrl">
跳转到统一验证接口http://check.x.com/sso/doLogin.action
验证用户名和密码。
统一验证接口返回 cookie
之前,必须设置
// 由 . 开头,则只有子域名可用。若无,则主域名和子域名可用cookie.setDomain(".x.com"); // 同一父域名cookie.setPath("/");
浏览器保存cookie
后,带着cookie
跳转回 http://demo1.x.com/demo1/main.action
要设置setDomain()
,否则请求无法携带cookie
服务器之间的通信
当http://demo1.x.com/demo1/main.action
的服务器接收到cookie
时,将cookie名
和cookie值
发给统一验证接口http://check.x.com/sso/checkCookie.action
处理,约定好返回值是什么,成功返回后判断是否让其访问资源。
可通过 HttpURLConnection 类或者使用 HttpClient 客户端进行通信。
完全跨域 SSO 登录
即域名完全不同,如www.a.com
和www.b.com
登录验证
进入www.a.com
资源页面,查看cookie
,若无,则跳转登录页面。
www.a.com
服务器接收用户信息数据,但不验证,将用户信息数据传输http://www.x.com/sso/doLogin.action
验证。
<form action="/doLogin.action"></form>
进入 action
类,根据代码逻辑与验证服务器通信
result = SSOUtil.post(checkSSOUrl, username, password);
验证成功后返回信息给www.a.com
,判断可访问资源后并向浏览器发送 cookie
存放确认用户身份的 token
(即 cookieValue)
Cookie cookie = new Cookie(cookieName, cookieValue);HttpServletResponse response = ServletActionContext.getResponse();response.addCookie(cookie);
分发 cookie
问题此cookie
只有www.a.com
才能访问,所以,需要在确定用户身份后,访问资源页面时向www.b.com
发送请求,并让www.b.com
向浏览器发送cookie
的值
在www.a.com
与www.b.com
的action
类里添加方法,传送兄弟 URL 和传参,则无论是访问 a 或 b ,登录成功后在cookie
有效期内都能访问 b 或 a 的资源。
List<String> urlList; // 存放兄弟 URLString cookieName;String cookieValue;...// Struts2 的 OGNLsetter/getter...public String main() { ... urlList.add("www.b.com/demo2/pushCookieToBrowser.action" + "?cookieName=" + cookieName + "&cookieValue=" + cookieValue); ...}public void pushCookieToBrowser() { HttpServletRequest request = ServletActionContext.getRequest(); this.cookieName = request.getParameter("cookieName"); this.cookieValue = request.getParameter("cookieValue"); Cookie cookie = new Cookie(cookieName, cookieValue); HttpServletResponse response = ServletActionContext.getResponse(); response.addCookie(cookie);}
在登录成功的资源页面使用 <iframe>
将返回数据信息循环请求发给兄弟服务器域名,让兄弟域名向浏览器发送 cookie
,完成跨域 SSO
www.a.com
loginSuccess.jsp
<c:forEach var="url" items="${urlList}"> <%-- 隐藏 iframe --%> <iframe src="${url}" width="0px" hight="0px" style="dispaly: none"></iframe></c:forEach>
再访问 b 的资源时将不需要再次输入密码。
注意
- 核心是
Cookie
,需要注意设置的域、位置和安全性。 - 应用群的安全问题:木桶效应。
资料
慕课视频
单点登录原理与简单实现
- sso单点登录1
- sso单点登录2
- sso单点登录3
- SSO(单点登录)
- SSO单点登录
- 单点登录(SSO)
- SSO 单点登录
- SSO单点登录解决方案
- SSO单点登录解决方案
- SSO单点登录解决方案
- SSO单点登录
- SSO单点登录
- SSO单点登录解决方案
- 单点登录sso简介
- 单点登录SSO
- sso单点登录解决方案
- SSO单点登录技术
- 练习 单点登录(sso)
- day15泛型
- Python语法 之 结构与函数
- IDEA中maven项目导jar包太慢
- 一张图吃透android的TouchEvent事件传递
- 为什么很多人都选择 OS X + Vim + IntelliJ IDEA?
- SSO 单点登录
- Kaggle入门——使用scikit-learn解决DigitRecognition问题
- oracle 语句创建数据库
- 传智播客--刘意Java基础视频-深入浅出精华版
- 鞍点计算
- Linux管理员不可不知十大PHP安全要点
- Caffe源码阅读(粗读)--网络训练
- Android webview使用详解
- app与后台的token、sessionId、RSA加密登录认证与安全解决方案