首先贴出国内大神的开源SSO框架 KISSO

http://git.oschina.net/baomidou/kisso

废话不多说,开始~

贴一张KISSO文档上的原理图

其实就是用户在登录业务系统的时候。看一下本地是否有Cookie

如果没有Cookie。访问SSO项目。SSO也没有Cookie的话。

进行登录。登录成功将加密的Token写入Cookie

回传给业务系统。通过几次的加密。认证,双方认证OK后

在业务系统域名下写入Cookie。完成登录


一、KISSO服务器端集成(springMVC+redis)

1、maven依赖增加

<!-- kisso begin --><dependency><groupId>com.baomidou</groupId><artifactId>kisso</artifactId><version>3.6.10</version></dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk14</artifactId><version>1.50</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.1.46</version></dependency><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.0</version></dependency><!-- kisso end -->

2、web.xml(这里使用过滤器方式,不使用spring-mvc拦截器方式)

over.url:这里参数为不需要过滤器过滤的方法。

<!-- kisso --><context-param><param-name>kissoConfigLocation</param-name><param-value>classpath:properties/sso.properties</param-value></context-param><listener><listener-class>com.baomidou.kisso.web.KissoConfigListener</listener-class></listener><!-- SSOFilter --><filter><filter-name>SSOFilter</filter-name><filter-class>com.baomidou.kisso.web.filter.SSOFilter</filter-class><init-param><param-name>over.url</param-name><param-value>/phoneSms;/PhoneSmsCode;</param-value></init-param></filter><filter-mapping><filter-name>SSOFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

其实就是看本地有没有Cookie 。没有就跳转到SSO项目

public class SSOClientFilter implements Filter {private static final Logger logger = Logger.getLogger("SSOFilter");private static String OVERURL = null;public SSOClientFilter() {}public void init(FilterConfig config) throws ServletException {OVERURL = config.getInitParameter("over.url");}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest)request;HttpServletResponse res = (HttpServletResponse)response;boolean isOver = HttpUtil.inContainURL(req, OVERURL);if(!isOver) {Token token = SSOHelper.getToken(req);if(token == null) {logger.fine("logout. request url:" + req.getRequestURL());SSOProperties prop = SSOConfig.getSSOProperties();String retStr = prop.get("sso.defined.proxyloginurl");
//                String retUrl = HttpUtil.getQueryString(req, "UTF-8");
//                this.logger.fine("loginAgain redirect pageUrl.." + retUrl);res.sendRedirect(HttpUtil.encodeRetURL(prop.get("sso.login.url"), "ReturnURL", retStr));return;}SsoUser user = (SsoUser) req.getSession().getAttribute(UserConstants.LOGIN_USER);if(user == null){SSOHelper.logout(req,res);return;}req.setAttribute("SSOTokenAttr", token);}chain.doFilter(request, response);}public void destroy() {OVERURL = null;}
}

3、KISSO的配置文件 sso.properties

这里具体就不贴出来了。 查阅一下文档写的非常详细

################ SSOConfig file #################
sso.role=应用名
sso.secretkey=秘钥
sso.cookie.domain=cookie存储的位置
sso.login.url=登录的url#cookie setting# crossdomain secretkey
sso.authcookie.secretkey=跨域对称加密的秘钥#cache
sso.cache.class=缓存实现类。实现SSOCache接口
sso.cache.expires=有效时间# userConfig defined
sso.defined.my_public_key=业务系统的公钥(校验业务系统)
sso.defined.sso_private_key=SSO系统的私钥(加密使用)

4、服务端控制层

@Controller
public class SsoController {private static Logger log = Logger.getLogger(SsoController.class);@Autowiredprivate SsoUserService ssoUserService;protected String redirectTo(String url) {StringBuffer rto = new StringBuffer("redirect:");rto.append(url);return rto.toString();}/*** 登录 (注解跳过权限验证)*/@Login(action = Action.Skip)@RequestMapping("/login")public String login(RedirectAttributesModelMap modelMap, Model model, HttpServletRequest request, HttpServletResponse response) {log.info("登录 (注解跳过权限验证)");String returnUrl = request.getParameter(SSOConfig.getInstance().getParamReturl());Token token = SSOHelper.getToken(request);if (token == null) {/*** 正常登录 需要过滤sql及脚本注入*/WafRequestWrapper wr = new WafRequestWrapper(request);String loginUser = wr.getParameter("loginUser");String loginPass = wr.getParameter("loginPass");//定义校验失败标识符boolean falg = false;//定义校验失败的字符串String falgStr = "";if (loginUser != null && !"".equals(loginUser)) {SsoUser user = ssoUserService.findByName(loginUser);if(user != null){if(user.getPassword().equals(Md5Util.MD5Encode(loginPass))){/** 设置登录 Cookie* 最后一个参数 true 时添加 cookie 同时销毁当前 JSESSIONID 创建信任的 JSESSIONID*/SSOToken st = new SSOToken(request, user.getId()+"");
//                        st.setData("jjc看源码哦");//记住密码就设置//SSOConfig.getInstance().setCookieMaxage(604800);SSOHelper.setSSOCookie(request, response, st, true);}else{//证明密码不匹配falg = true;falgStr = "密码不正确";}}else{//证明没有用户名falg = true;falgStr = "用户名不正确";}} else {falg = true;falgStr = "";}if(falg){//校验失败。跳转回登录页model.addAttribute("msg", falgStr);if (StringUtils.isNotEmpty(returnUrl)) {model.addAttribute("ReturnURL", returnUrl);}model.addAttribute("loginUser", loginUser);model.addAttribute("loginPass", loginPass);return "login";}else{//校验成功,重定向到业务系统// 重定向到指定地址 returnUrlif (StringUtils.isEmpty(returnUrl)) {returnUrl = "/index.html";} else {returnUrl = HttpUtil.decodeURL(returnUrl);}return redirectTo(returnUrl);}} else {if (StringUtils.isEmpty(returnUrl)) {returnUrl = "/index.html";}return redirectTo(returnUrl);}}@ResponseBody@RequestMapping("/replylogin")public void replylogin(HttpServletRequest request, HttpServletResponse response) {log.info("SSO回复子系统");StringBuffer replyData = new StringBuffer();replyData.append(request.getParameter("callback")).append("({\"msg\":\"");Token token = SSOHelper.getToken(request);if (token != null) {String askData = request.getParameter("askData");if (askData != null && !"".equals(askData)) {/**** 用户自定义配置获取** <p>* 由于不确定性,kisso 提倡,用户自己定义配置。* </p>**/SSOProperties prop = SSOConfig.getSSOProperties();//下面开始验证票据,签名新的票据每一步都必须有。AuthToken at = SSOHelper.replyCiphertext(request, askData);if (at != null) {//1、业务系统公钥验证签名合法性(此处要支持多个跨域端,取 authToken 的 app 名找到对应系统公钥验证签名)at = at.verify(prop.get("sso.defined." + at.getApp() + "_public_key"));if (at != null) {//at.getUuid() 作为 key 设置 authToken 至分布式缓存中,然后 sso 系统二次验证//at.setData(data); 设置自定义信息,当然你也可以直接 at.setData(token.jsonToken()); 把当前 SSOToken 传过去。at.setUid(token.getUid());//设置绑定用户IDat.setTime(token.getTime());//设置登录时间//2、SSO 的私钥签名at.sign(prop.get("sso.defined.sso_private_key"));//3、生成回复密文票据replyData.append(at.encryptAuthToken());} else {//非法签名, 可以重定向至无权限界面,自己处理replyData.append("-2");}} else {//非法签名, 可以重定向至无权限界面,自己处理replyData.append("-2");}}} else {// 未登录replyData.append("-1");}try {replyData.append("\"})");AjaxHelper.outPrint(response, replyData.toString(), "UTF-8");} catch (IOException e) {e.printStackTrace();}}/*** 统一退出,调用对外提供退出的所有接口*/@RequestMapping("/logout")public String logout(HttpServletRequest request,HttpServletResponse response) {SSOHelper.clearLogin(request, response);return "logout";}/***/@RequestMapping("/index")public String index(HttpServletRequest request,HttpServletResponse response) {return "index";}
}

5、redis集成(退出使用,具体请查阅官方文档)

public class SSORedisCaChe implements SSOCache {

StringRedisTemplate stringRedisTemplate = (StringRedisTemplate) WebApplicationContextHelper.getBean("stringRedisTemplate");@Override
public Token get(String s, int i) {if(exists(s)){String result = null;ValueOperations operations = stringRedisTemplate.opsForValue();result = (String)operations.get(s);result = result.replaceAll("\u0000" , "");Token token = SSOConfig.getInstance().getParser().parseObject(result, Token.class);return  token;}return null;
}@Override
public boolean set(String s, Token token, int i) {boolean result = false;try {delete(s);ValueOperations valueOperations = stringRedisTemplate.opsForValue();valueOperations.set(s,token.jsonToken(),i);result = true;} catch (Exception e) {e.printStackTrace();}return result;}@Override
public boolean delete(String s) {boolean result = false;try{if (exists(s)) {stringRedisTemplate.delete(s);return  true;}}catch (Exception e){e.printStackTrace();}return result;
}public boolean exists(final String key) {return stringRedisTemplate.hasKey(key);
}

}

二、客户端集成

1、maven一致
2、web.xml

SSOClientFilter 客户端自定义的过滤器。模仿kisso的过滤器

<!-- kisso --><context-param><param-name>kissoConfigLocation</param-name><param-value>classpath:properties/sso.properties</param-value></context-param><listener><listener-class>com.baomidou.kisso.web.KissoConfigListener</listener-class></listener><!-- SSOFilter --><filter><filter-name>SSOClientFilter</filter-name><filter-class>com.hc360.yunxin.filter.SSOClientFilter</filter-class><init-param><param-name>over.url</param-name><param-value>/login;/verify;/resources/;/code;/proxylogin;/oklogin;/accountsecurity/mailboxBound;/accountsecurity/mailboxBoundUpdate</param-value></init-param></filter><filter-mapping><filter-name>SSOClientFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

3、sso.properties

################ SSOConfig file #################
sso.role=业务系统名字 , 拼接使用
sso.secretkey=加密秘钥
sso.cookie.domain=写入cookie地址
sso.login.url=登录url-》跳转SSO
sso.logout.url=登出url
# crossdomain secretkey
sso.authcookie.secretkey=#cache
sso.cache.class=缓存
sso.cache.expires=失效时间 秒单位# userConfig defined
sso.defined.proxyloginurl=sso回复客户端的地址
sso.defined.askurl=sso认证地址
sso.defined.oklogin=客户端写入cookie的actionsso.defined.clientIndex=客户端自己的主页
sso.defined.clientTimeout=自定义超时链接sso.defined.my_private_key=业务系统的私钥
sso.defined.my_public_key=业务系统的公钥
sso.defined.sso_public_key=sso系统的公钥

4、客户端Controller

@Controller
public class SsoController {@Autowiredprivate SsoUserService ssoUserService;protected String redirectTo(String url) {StringBuffer rto = new StringBuffer("redirect:");rto.append(url);return rto.toString();}@RequestMapping("/index")public String index(Model model, HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {Token token = SSOHelper.getToken(request);response.setCharacterEncoding("UTF-8");request.setCharacterEncoding("UTF-8");if (token == null) {/*** 重定向至代理跨域地址页*/return redirectTo("http://sso.test.com:8081/kisso_crossdomain_sso/login.html?ReturnURL=http%3A%2F%2Fmy.web.com%3A8082%2F/kisso_crossdomain_my/proxylogin.html");} else {
//            model.addAttribute("userId", token.getUid());SsoUser SessionssoUser = (SsoUser) request.getSession().getAttribute(UserConstants.LOGIN_USER);model.addAttribute("user",  ssoUserService.findByID(SessionssoUser.getId()));}return "index";}/*** 跨域登录*/@RequestMapping("/proxylogin")public String proxylogin(Model model,HttpServletRequest request,HttpServletResponse response) {/**** 用户自定义配置获取** <p>* 由于不确定性,kisso 提倡,用户自己定义配置。* </p>**/SSOProperties prop = SSOConfig.getSSOProperties();//业务系统私钥签名 authToken 自动设置临时会话 cookie 授权后自动销毁AuthToken at = SSOHelper.askCiphertext(request, response, prop.get("sso.defined.my_private_key"));//at.getUuid() 作为 key 设置 authToken 至分布式缓存中,然后 sso 系统二次验证//askurl 询问 sso 是否登录地址model.addAttribute("askurl", prop.get("sso.defined.askurl"));//askTxt 询问 token 密文model.addAttribute("askData", at.encryptAuthToken());//my 确定是否登录地址model.addAttribute("okurl", prop.get("sso.defined.oklogin"));return "proxylogin";}/*** 跨域登录成功*/@ResponseBody@RequestMapping("/oklogin")public void oklogin( HttpServletRequest request,HttpServletResponse response) {SSOProperties prop = SSOConfig.getSSOProperties();//String returl = prop.get("sso.defined.clientTimeout");String returl =prop.get("sso.logout.url");/** <p>* 回复密文是否存在* </p>* <p>* SSO 公钥验证回复密文是否正确* </p>* <p>* 设置 业务系统自己的 Cookie* </p>*/String replyTxt = request.getParameter("replyTxt");if (replyTxt != null && !"".equals(replyTxt)) {AuthToken at = SSOHelper.ok(request, response, replyTxt, prop.get("sso.defined.my_public_key"),prop.get("sso.defined.sso_public_key"));if (at != null) {returl = prop.get("sso.defined.clientIndex");SSOToken st = new SSOToken();st.setUid(at.getUid());st.setTime(at.getTime());
//                st.setData(at.getData());/** 设置 true 时添加 cookie 同时销毁当前 JSESSIONID 创建信任的 JSESSIONID*/SSOHelper.setSSOCookie(request, response, st, true);//设置完Cookie  设置Sessionrequest.getSession().setAttribute(UserConstants.LOGIN_USER, ssoUserService.findByID(Integer.parseInt(at.getUid())));}}try {AjaxHelper.outPrint(response, "{\"returl\":\"" + returl + "\"}", "UTF-8");} catch (IOException e) {e.printStackTrace();}}/*** 跨域登录超时*/@RequestMapping("/timeout")public String timeout() {return "timeout";}/*** 如果实现 SSOCache 缓存, kisso 自动缓存 token 退出只需要 SSOHelper.clearLogin(request, response);** 自动清理 token 缓存信息, 同时各个系统都会自动退出。 建议这么!!退出更优雅。。。** --------------- 悲剧的开启 ---------------** 如果你不这么干那么您只能挨个不同域退出一遍,最终全站退出。**/@RequestMapping("/logout")public String logout( HttpServletRequest request,HttpServletResponse response) {/*** <p>* SSO 退出,清空退出状态即可* </p>** <p>* 子系统退出 SSOHelper.logout(request, response); 注意 sso.properties 包含 退出到* SSO 的地址 , 属性 sso.logout.url 的配置* </p>*/SSOHelper.clearLogin(request, response);return "redirect:/index";}}

5、redis与服务一致

6、客户端发送跨域,请求SSO认证的静态页面

<body>
<script type="text/javascript">function proxyLogin(askurl, askData, okurl) {var killAjax = true;
//      setTimeout(function() {//          checkajaxkill();
//      }, 30000);var ajaxCall = jQuery.getJSON(askurl + "?callback=?", {askData:askData}, function(d){killAjax = false;if(d.msg == "-1"){window.location.href = SSOLoginUrl;}else{jQuery.post(okurl, {replyTxt:d.msg} , function(e) {window.location.href = e.returl;}, "json");}});
//      function checkajaxkill(){//          if(killAjax){//              ajaxCall.abort();
//              window.location.href = SSOTimeout;
//          }
//      }}proxyLogin("$!{askurl}", "$!{askData}", "$!{okurl}");
</script>
<div align="center" style="margin-top: 180px;"><img src="resources/img/loading.gif"> 页面正在加载中,请稍候……
</div>
</body>

登录总结流程:

1、用户访问业务系统,通过自定义拦截器跳转到SSO系统进行认证。

2、在SSO系统登陆成功后。进行浏览器重定向

3、重定向到业务系统的Controller

4、业务系统的Controller将自己的私钥加密临时会话Cookie信息,发送给SSO进行认证。(认证时需要使用JSONP方式跨域发送请求 KISSO框架处理方式)

5、SSO系统首先会看看自己本地是否有Cookie,如果有的话将加密信息进行解密,拿到信息中业务系统的名字,拼接配置文件的配置。拿到业务系统公钥进行校验。 成功后在使用SSO系统的私钥进行加密信息返回

6、JSONP消息拿到后,使用业务系统的公钥以及SSO系统的公钥校验回传的信息是否正确。无问题后。将本地设置好Cookie uid 并跳转业务系统

登出流程总结:

根据KISSO的接口自定义Cache通过集成Redis保存加密Token
通过以下方法进行登出
SSOHelarLogin(request, response);
原理:
将Redis中的数据清除后,其他系统在操作时通过KISSO的过滤器会通过自定义cache读取缓存信息,如数据清除。将清除其他系统本地的Cookie。

SSO搭建(框架KISSO)相关推荐

  1. ssm radis mysql_从零开始搭建框架SSM+Redis+Mysql(一)之摘要

    从零开始搭建框架SSM+Redis+Mysql(一)之摘要 本文章为本人实际的操作后的回忆笔记,如果有步骤错漏,希望来信307793969@qq.com或者评论指出. 本文章只体现过程,仅体现操作流程 ...

  2. Angular搭建框架比较好用的插件

    以下是我在搭建框架时所使用的一些插件,欢迎补充! UI Bootstrap 整合了Bootstrap 一些组件功能,比较强大 UI Calendar Angular UI Grid 功能比较强大,比n ...

  3. 一线开发大牛带你初步了解如何使用SpringBoot搭建框架

    Spring Boot基础 本文以实战为导向,讲解了如何使用Spring Cloud开发微服务项目,而Spring Cloud基于SpringBoot,所以本篇先来初步了解如何使用Spring Boo ...

  4. 个人博客搭建——介绍几种博客搭建框架

    介绍几种个人博客的搭建框架 1.hexo:https://hexo.io/ Hexo 是一个快速.简洁且高效的博客框架.Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓 ...

  5. 【uni-app系列】uni-app之快速搭建框架

    目录 一.uni-app 是什么? 二.为什么选择 uni-app ? 三.功能框架 四.准备工作 五.搭建框架 1.创建项目 2.运行项目 (1)运行到浏览器 (2)内置浏览器运行 (3)运行到手机 ...

  6. .net MVC5+EF6+bootstrap搭建框架,从入门到精通(三)——之(Bootstrap Fileinput)多图片上传

    .net MVC5+EF6+bootstrap搭建框架,从入门到精通(三)--之(Bootstrap Fileinput)多图片上传 前言废话 .net mvc 实战多图片上传 前言废话 人生最大的b ...

  7. java 详解 搭建 框架_maven 基本框架搭建详解

    在平时的开发中还是在写blog时,在项目实例开始都会需要一遍一遍的介绍maven框架搭建,重复性的工作让我觉得烦恼,现在展现一下Java的核心思想"重复利用",将这个重复性的描述提 ...

  8. Drupal8系列(五):主题制作之搭建框架-Ubuntu 14.04 LTS

    Drupal8的主题制作准备工作已经完成了,那么我们接下来就开始正式制作主题了! 一.生成主题的Compass框架 首先我们先进入到Druapl8的主题目录: cd /var/www/druapl8/ ...

  9. java 详解 搭建 框架_在Eclipse中搭建Struts框架过程详解

    虽然用MyEclipse搭建Struts框架是更为便捷的方式,但是用Eclipse可以增强自己对Struts的理解.本文演示了使用Eclipse搭建Struts 1.2框架的过程.此项目实现了简单的功 ...

最新文章

  1. 【spring】自动装配
  2. 出色管理者的时间管理
  3. 吴恩达、李飞飞、沈向洋:2021年的人工智能将会如何发展?
  4. python os.path.exists()(用于判断文件夹路径是否存在)
  5. Boost:Porthopper服务测试程序
  6. OpenCV-图像特征harris角点检测/SIFT函数/特征匹配-05
  7. 如何在运行时打印出 SAP Spartacus 配置(config)信息
  8. 预测:小程序入口预测汇总(8种可能)
  9. 2个维度5大方法,让你的微服务在K8s上跑起来
  10. 滚动监听 after选择器
  11. 12. Copy all parts of an object
  12. abb机器人goto指令用法_abb机器人编程指令,机器人编程的程序指令
  13. 一文盘点中国商业航天:民营火箭的两类瓶颈和三大趋势
  14. TSO/GSO/LRO/GRO
  15. ORA-20011, KUP-11024 外部表引发报错
  16. python 批量下载 代码_Python实现的批量下载RFC文档
  17. 某项目的双代号网络图如下所示_某工程项目的双代号网络计划如下图所示(时间单位:月)。...
  18. 香港银行账户被关,应如何取走余额
  19. Python杀死了Excel
  20. Gzip的动态压缩和静态压缩详解

热门文章

  1. keycode键盘 按键 - 键码 对应表
  2. 自动化测试面试题及答案(一)
  3. chrome 网页截取全图
  4. 在Node服务器中运行html文件
  5. mac 安装oracle
  6. 关于搭建代理服务器的全过程详细
  7. IOS 某电商App签名算法解析(二) Frida RPC调用
  8. cocos-js 移花接木-用旧资源替换新创建的项目
  9. 第10周项目 2.2 传字条
  10. 小程序转盘抽奖,小程序抽奖