热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

自己动手写SSO单点注销服务端和客户端

本文为转载,发表在:https:www.jianshu.comp667c8f0b514f一、前言单点登录自然也要单点注销,在一个子系统中注销,所有子系统的会话都将被销毁,用下面的图

本文为转载 ,发表在: https://www.jianshu.com/p/667c8f0b514f

 

一、前言

单点登录自然也要单点注销,在一个子系统中注销,所有子系统的会话都将被销毁,用下面的图来说明。单点注销难点在于在其中一个系统注销之后,需要把其他的子系统的会话销毁.所以肯定需要子系统在令牌校验通过之后,统一认证中心要把该子系统的地址和会话记录起来.才能在注销的时候找到这些子系统通,依次调用子系统通的注销方法,销毁局部会话.

二、单点注销流程图


三、代码实现

客户端(注意:两个客户端项目都得改):

步骤:

1.在两个客户端项目中修改main.jsp,让退出的地址映射到统一认证中心的登出方法.


退出

2.在SSOClientFilter.java校验令牌信息token的时候,还需要把该系统的登出地址和该系统的会话id一并的发送到统一认证中心.修改SSOClientFilter.javadoFilter方法


@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse resp = (HttpServletResponse) response;HttpSession session = req.getSession();//1.判断是否有局部的会话Boolean isLogin = (Boolean) session.getAttribute("isLogin");if(isLogin!=null && isLogin){//有局部会话,直接放行.chain.doFilter(request, response);return;}//判断地址栏中是否有携带token参数.String token = req.getParameter("token");if(StringUtils.isNoneBlank(token)){//token信息不为null,说明地址中包含了token,拥有令牌.//判断token信息是否由认证中心产生的.//验证地址为:http://www.sso.com:8443/verifyString httpURL = SSOClientUtil.SERVER_URL_PREFIX+"/verify";Map params = new HashMap();//把客户端地址栏添加到的token信息传递给统一认证中心进行校验params.put("token", token);/**-------------------------阶段四添加的代码start---------------------------------**///获取客户端的完整登出地址 http://www.crm.com:8088/logOutparams.put("clientUrl", SSOClientUtil.getClientLogOutUrl());params.put("jsessionid", session.getId());/**-------------------------阶段四添加的代码end---------------------------------**/try {String isVerify = HttpUtil.sendHttpRequest(httpURL, params);if("true".equals(isVerify)){//如果返回的字符串是true,说明这个token是由统一认证中心产生的.//创建局部的会话.session.setAttribute("isLogin", true);//放行该次的请求chain.doFilter(request, response);return;}} catch (Exception e) {//这里可以完善,比如出现异常在前台显示具体页面//我们这个案例就不做这个哈.e.printStackTrace();}}//没有局部会话,重定向到统一认证中心,检查是否有其他的系统已经登录过.// http://www.sso.com:8443/checkLogin?redirectUrl=http://www.crm.com:8088SSOClientUtil.redirectToSSOURL(req, resp);}

服务端:

步骤:

1.在MockDatabaseUtil.java中模拟表t_client_info存储已注册的子系统信息,创建ClientInfoVo.java封装客户端信息


package cn.wolfcode.sso.vo;
import lombok.Getter;
import lombok.Setter;
/*** Created by wolfcode-lanxw*/
@Setter@Getter
public class ClientInfoVo {private String clientUrl;//客户端登出地址private String jsessionid;//客户端会话id
}

MockDatabaseUtil.java中模拟表t_client_info的信息.


public class MockDatabaseUtil {//模拟数据库中的t_token表public static Set T_TOKEN = new HashSet();//模拟数据库中的t_client_info表public static Map> T_CLIENT_INFO =new HashMap>();
}

2.需要在SSOServerController.java修改verifyToken方法的逻辑,获取客户端传过来的令牌信息(token),客户端登出地址(clientUrl),客户端的会话id(jsessionid),并且需要把客户端地址存储起来.


@RequestMapping("/verify")@ResponseBodypublic String verifyToken(String token,String clientUrl,String jsessionid){//在模拟的数据库表t_token中查找是否有这条记录if(MockDatabaseUtil.T_TOKEN.contains(token)){//根据token获取客户端的登出地址记录集合List clientInfoList = MockDatabaseUtil.T_CLIENT_INFO.get(token);if(clientInfoList==null){//第一个系统注册的时候获取出来的集合空的,所以需要创建一个clientInfoList = new ArrayList();//创建好之后需要放入到map中,方便后续的获取MockDatabaseUtil.T_CLIENT_INFO.put(token,clientInfoList);}//封装客户端的信息ClientInfoVo vo = new ClientInfoVo();vo.setClientUrl(clientUrl);vo.setJsessionid(jsessionid);//把当前的客户端地址注册到集合中.clientInfoList.add(vo);//说明令牌有效,返回truereturn "true";}return "false";}

3.在SSOServerController.java添加一个统一认证中心登录的方法logOut


@RequestMapping("/logOut")public String logOut(HttpSession session){//销毁全局会话session.invalidate();return "logOut";}

4.拷贝之前客户端工具类HttpUtil.java到项目中

5.创建MySessionListener.java,监听session的销毁事件,当全局会话销毁的时候,获取全局会话中的令牌信息token,通过token信息查询t_client_info表,获取已注册的子系统集合,遍历子系统集合,依次调用子系统的登出方法.

6.清空t_token表数据,清空t_client_info表数据


package cn.wolfcode.sso.listener;import cn.wolfcode.sso.util.HttpUtil;
import cn.wolfcode.sso.util.MockDatabaseUtil;
import cn.wolfcode.sso.vo.ClientInfoVo;import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.List;/*** Created by wolfcode-lanxw*/
@WebListener
public class MySessionListener implements HttpSessionListener {@Overridepublic void sessionCreated(HttpSessionEvent se) {}//监听session的销毁事件@Overridepublic void sessionDestroyed(HttpSessionEvent se) {HttpSession session = se.getSession();//获取会话中的令牌信息String token = (String) session.getAttribute("token");//删除t_token表中的数据MockDatabaseUtil.T_TOKEN.remove(token);//删除t_client_info表中的数据List clientInfoVoList = MockDatabaseUtil.T_CLIENT_INFO.remove(token);try{for(ClientInfoVo vo:clientInfoVoList){//获取出注册的子系统,依次调用子系统的登出的方法HttpUtil.sendHttpRequest(vo.getClientUrl(),vo.getJsessionid());}}catch(Exception e){e.printStackTrace();;}}
}

四、单点注销流程梳理

客户端:


1.在登陆的按钮链接写上统一认证中心的登出方法即可.
退出
2.校验令牌信息的同时把客户端登出地址(clientUrl)和客户端会话id(jsession)一并的传到统一认证中心

服务端:


1.编写logOut方法,调用session.invalidate()2.创建session的监听器,在session的监听器的销毁方法写如下逻辑2.1获取session中的token.2.2根据token获取所有客户端的登出地址和会话id2.3通过HttpUtil选项调用客户端的登出方法.

五、测试

在服务端和两个客户端运行tomcat7:run命令.

在浏览器中按下Ctrl+Shift+Delete按键清楚COOKIE和缓存,避免干扰.

1.访问http://www.crm.com:8088/main,跳转到统一认证中心登录界面.

2.输入账号密码,放行请求,访问到CRM系统的main.jsp页面.

3.在同一浏览器中打开多个窗口输入http://www.wms.com:8089/main,都是放行请求.

4.点击CRM系统中的退出按钮,显示系统已注销

5.在同一浏览器中打开http://www.wms.com:8089/main,此时就跳转到统一认证中心的登陆页面.

如果测试结果和上述一致,说明单点注销功能也完成了.

六、代码下载

熟悉git命令的同学:

客户端单点注销Demo:


git reset --hard 5631a13ecfd0b73bfc27adaa34ba0fd6fe01b2fb

客户端2单点注销Demo:


git reset --hard 01db6af390ff9f765121d3f9e9b1895b0e671bd5

服务端单点注销Demo:


git reset --hard 5d619c5065cabd83a16d5b4d34e3c89a5950fb5b

不熟悉git命令的同学

客户端单点注销Demo
客户端2单点注销Demo
服务端单点注销Demo


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • Java程序设计第4周学习总结及注释应用的开发笔记
    本文由编程笔记#小编为大家整理,主要介绍了201521123087《Java程序设计》第4周学习总结相关的知识,包括注释的应用和使用类的注释与方法的注释进行注释的方法,并在Eclipse中查看。摘要内容大约为150字,提供了一定的参考价值。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
author-avatar
一生一世0521
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有