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

本文介绍了如何使用Java实现单点登出(SSO)功能,包括服务端和客户端的代码实现。在单点注销过程中,通过在客户端修改登出链接、将登出地址和会话ID发送到统一认证中心,然后在服务端监听session销毁,调用各子系统的登出方法,完成全局会话销毁。
摘要由CSDN通过智能技术生成

一、前言

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

二、单点注销流程图

52a5c22b8ef3f11befedd2407ee15d69.png

0d684f0e240826901076a7e814b26e13.png

三、代码实现

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

步骤:

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

退出

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

@Override

public 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/verify

String httpURL = SSOClientUtil.SERVER_URL_PREFIX+"/verify";

Map params = new HashMap();

//把客户端地址栏添加到的token信息传递给统一认证中心进行校验

params.put("token", token);

/**-------------------------阶段四添加的代码start---------------------------------**/

//获取客户端的完整登出地址 http://www.crm.com:8088/logOut

params.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:8088

SSOClientUtil.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")

@ResponseBody

public 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);

//说明令牌有效,返回true

return "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 {

@Override

public void sessionCreated(HttpSessionEvent se) {

}

//监听session的销毁事件

@Override

public 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获取所有客户端的登出地址和会话id

2.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命令的同学

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值