有关单点登录(SSO)之前有写过两篇文章

如果说XXL-JOB你可能并不陌生,它是非常火爆的一个分布式任务调度平台。但其实在该作者还有一个非常优秀的开源项目叫XXL-SSO,这两个个项目都是1000+Star。

XXL-SSO 是一个分布式单点登录框架。只需要登录一次就可以访问所有相互信任的应用系统。 拥有"轻量级、分布式、跨域、Cookie+Token均支持、Web+APP均支持"等特性。现已开放源代码,开箱即用。

这里主要是通过对XXL-SSO源码的分析,将理论和实践结合!

一、快速接入sso

1、xxl-sso特性

  1. 简洁:API直观简洁,可快速上手
  2. 轻量级:环境依赖小,部署与接入成本较低
  3. 单点登录:只需要登录一次就可以访问所有相互信任的应用系统
  4. 分布式:接入SSO认证中心的应用,支持分布式部署
  5. HA:Server端与Client端,均支持集群部署,提高系统可用性
  6. 跨域:支持跨域应用接入SSO认证中心
  7. Cookie+Token均支持:支持基于Cookie和基于Token两种接入方式,并均提供Sample项目
  8. Web+APP均支持:支持Web和APP接入
  9. 实时性:系统登陆、注销状态,全部Server与Client端实时共享
  10. CS结构:基于CS结构,包括Server"认证中心"与Client"受保护应用"
  11. 记住密码:未记住密码时,关闭浏览器则登录态失效;记住密码时,支持登录态自动延期,在自定义延期时间的基础上,原则上可以无限延期
  12. 路径排除:支持自定义多个排除路径,支持Ant表达式,用于排除SSO客户端不需要过滤的路径

2、环境

  • JDK:1.7+
  • Redis:4.0+

3、 源码地址

4、 项目结构说明

- xxl-sso-server:中央认证服务,支持集群
- xxl-sso-core:Client端依赖
- xxl-sso-samples:单点登陆Client端接入示例项目
- xxl-sso-web-sample-springboot:基于Cookie接入方式,供用户浏览器访问,springboot版本
- xxl-sso-token-sample-springboot:基于Token接入方式,常用于无法使用Cookie的场景使用,如APP、Cookie被禁

5、 架构图

应用系统:sso-web系统(8081端口)、sso-web系统(8082端口)(需要登录的系统)

SSO客户端:登录、退出(独立jar包给应用系统引用)

SSO服务端:登录(登录服务)、登录状态(提供登录状态校验/登录信息查询的服务)、退出(用户注销服务)

数据库:存储用户账户信息(一般使用Mysql,在当前项目中为了简便并没有查询数据库)

缓存:存储用户的登录信息(使用Redis)

二、快速接入XXL-SSO框架

1、 部署认证中心(sso-server)

只需要修改配置文件即可,配置文件位置:application.properties

## 配置redis
xxl.sso.redis.address=redis://118.31.224.65:6379
## 登录态有效期窗口,默认24H,当登录态有效期窗口过半时,自动顺延一个周期
xxl.sso.redis.expire.minute=1440

2、 部署'单点登陆Client端接入示例项目'

这里指需要接入SSO的系统,在当前项目有xxl-sso-web-sample-springboot和 xxl-sso-token-sample-springboot两个示例项目,这里暂且以sso-web为示例。

1)、maven依赖

<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-sso-core</artifactId>
<version>${最新稳定版}</version>
</dependency>

2)配置 XxlSsoFilter

参考代码:com.xxl.sso.sample.config.XxlSsoConfig

@Bean
public FilterRegistrationBean xxlSsoFilterRegistration() {
// xxl-sso, redis init
JedisUtil.init(xxlSsoRedisAddress);
// xxl-sso, filter init
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setName("XxlSsoWebFilter");
registration.setOrder(1);
registration.addUrlPatterns("/*");
registration.setFilter(new XxlSsoWebFilter());
registration.addInitParameter(Conf.SSO_SERVER, xxlSsoServer);
registration.addInitParameter(Conf.SSO_LOGOUT_PATH, xxlSsoLogoutPath);
return registration;
}
  1. application.properties修改
## 中央认证服务地址
xxl.sso.server=http://ssoserver.com:8080/xxl-sso-server
## 退出接口
xxl.sso.logout.path=/logout
## 排除走sso的接口
xxl-sso.excluded.paths=/excludedUrl
## redis地址
xxl.sso.redis.address=redis://118.11.214.65:6379

三、快速验证

1、修改host文件

修改Host文件:域名方式访问认证中心,模拟跨域与线上真实环境

127.0.0.1       ssoserver.com
127.0.0.1 webb.com
127.0.0.1 weba.com

2、启动项目

分别运行 “xxl-sso-server” 与 “xxl-sso-web-sample-springboot”,为了验证单点登录,这里sso-web需求启动两次,只是一次是8081端口,一次是8082端口。

## 1、SSO认证中心地址:
http://ssoserver.com:8080/xxl-sso-server
## 2、Client01应用地址:
http://weba.com:8081/xxl-sso-web-sample-springboot/
## 3、Client02应用地址:
http://webb.com:8082/xxl-sso-web-sample-springboot/

3、验证

SSO登录流程

正常情况下,登录流程如下:

1、访问 "Client01应用地址" ,将会自动 redirect 到 "SSO认证中心地址" 登录界面

2、成功登录后,将会自动 redirect 返回到 "Client01应用地址",并切换为已登录状态

3、此时,访问 "Client02应用地址",不需登陆将会自动切换为已登录状态

很明显Client01登录成功后,Client02无需再重新登录就可以访问了。

SSO注销流程

正常情况下,注销流程如下:

1、访问 "Client01应用地址" 配置的 "注销登陆path",将会自动 redirect 到 "SSO认证中心地址" 并自动注销登陆状态
2、此时,访问 "Client02应用地址",也将会自动注销登陆状态

四、核心代码分析

1、SSO客户端(sso-core)拦截器

主要看sso拦截器流程就可以了

 @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 获取当前请求接口
String servletPath = req.getServletPath();
// 1、是否是排除 不走sso的接口 如果是直接放行
if (excludedPaths != null && excludedPaths.trim().length() > 0) {
for (String excludedPath : excludedPaths.split(",")) {
String uriPattern = excludedPath.trim(); // 支持ANT表达式
if (antPathMatcher.match(uriPattern, servletPath)) {
// excluded path, allow
chain.doFilter(request, response);
return;
}
}
}
// 2、是否是退出登录接口
if (logoutPath != null
&& logoutPath.trim().length() > 0
&& logoutPath.equals(servletPath)) { // 2.1删除当前请求客户端的cookie
SsoWebLoginHelper.removeSessionIdByCookie(req, res);
// 2.2重定向到sso认证服务的 退出接口
String logoutPageUrl = ssoServer.concat(Conf.SSO_LOGOUT);
res.sendRedirect(logoutPageUrl);
return;
}
// 3、校验用户(是否存在,是否过期) 这个方法下面在展开
XxlSsoUser xxlUser = SsoWebLoginHelper.loginCheck(req, res);
// 4、令牌校验失败
if (xxlUser == null) {
//获取当前请求地址
String link = req.getRequestURL().toString();
// 重定向到sso认证服务的 登录接口
String loginPageUrl = ssoServer.concat(Conf.SSO_LOGIN)
+ "?" + Conf.REDIRECT_URL + "=" + link;
res.sendRedirect(loginPageUrl);
return;
}
// ser sso user
request.setAttribute(Conf.SSO_USER, xxlUser);
// 已经登录 放行
chain.doFilter(request, response);
return;
}

在看下上面的loginCheck方法

   /**
* 令牌校验
*
* @return 用户信息
*/
public static XxlSsoUser loginCheck(HttpServletRequest request, HttpServletResponse response){ //去cookie去获取xxl_sso_sessionid 其实就是之前原理篇说的token,只是名称叫法不同
String cookieSessionId = CookieUtil.getValue(request, Conf.SSO_SESSIONID); // 这里去redis中获取用户信息 有可能获取不到。这个方法就不粘贴了 这里有三种情况
//1、cookieSessionId为空 那么直接返回null
//2、cookieSessionId不为空,但在redis获取不到用户信息,因为存在其它系统退出后 redis删除了
//3、redis获取到了用户信息,但超过有效期了 依旧返回null
XxlSsoUser xxlUser = SsoTokenLoginHelper.loginCheck(cookieSessionId);
if (xxlUser != null) {
return xxlUser;
}
// 如果获取不到 所以已经在其它系统退出登录了 那删除cookie中的xxl_sso_sessionid
SsoWebLoginHelper.removeSessionIdByCookie(request, response);
//如果是 sso登录成功后 回调过来的 这个时候在这里是可以获取到xxl_sso_sessionid的
String paramSessionId = request.getParameter(Conf.SSO_SESSIONID);
xxlUser = SsoTokenLoginHelper.loginCheck(paramSessionId);
if (xxlUser != null) {
CookieUtil.set(response, Conf.SSO_SESSIONID, paramSessionId, false); /
return xxlUser;
}
return null;
}

2、认证服务器(sso-server)登录接口

  /**
* sso认证中心 登录接口
*/
@RequestMapping(Conf.SSO_LOGIN)
public String login(Model model, HttpServletRequest request, HttpServletResponse response) { // 同样的 该判断sso上有没有全局会话
XxlSsoUser xxlUser = SsoWebLoginHelper.loginCheck(request, response);
//如果 其它系统登录成功过 这个就不回为null 直接再带上xxl_sso_sessionid=xxx 重定向到之前接口
//也不用在登录了
if (xxlUser != null) {
// success redirect
String redirectUrl = request.getParameter(Conf.REDIRECT_URL);
if (redirectUrl!=null && redirectUrl.trim().length()>0) { String sessionId = SsoWebLoginHelper.getSessionIdByCookie(request);
String redirectUrlFinal = redirectUrl + "?" + Conf.SSO_SESSIONID + "=" + sessionId;;
return "redirect:" + redirectUrlFinal;
} else {
return "redirect:/";
}
}
//只有全局会话不存在 才会跳转登录页面
model.addAttribute("errorMsg", request.getParameter("errorMsg"));
model.addAttribute(Conf.REDIRECT_URL, request.getParameter(Conf.REDIRECT_URL));
return "login";
}

3、认证服务器(sso-server)退出接口

 @RequestMapping(Conf.SSO_LOGOUT)
public String logout(HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttributes) {
// 退出操作
SsoWebLoginHelper.logout(request, response);
// 跳转到登录页
redirectAttributes.addAttribute(Conf.REDIRECT_URL, request.getParameter(Conf.REDIRECT_URL));
return "redirect:/login";
}

再来看下 logout 方法做了哪些事情

 public static void logout(HttpServletRequest request,
HttpServletResponse response) { String cookieSessionId = CookieUtil.getValue(request, Conf.SSO_SESSIONID);
if (cookieSessionId==null) {
return;
}
//1、删除全局缓存 redis中 清除cookieSessionId,这样其它系统在令牌校验的时候 会失败。即一处退出,处处退出。
String storeKey = SsoSessionIdHelper.parseStoreKey(cookieSessionId);
if (storeKey != null) {
SsoLoginStore.remove(storeKey);
}
//2、清除全局会话
CookieUtil.remove(request, response, Conf.SSO_SESSIONID);
}

整个核心代码的逻辑都在这里了,其实结合上一篇的理论篇,理解起来就一点也不复杂了。

声明: 公众号如需转载该篇文章,发表文章的头部一定要 告知是转至公众号: 后端元宇宙。同时也可以问本人要markdown原稿和原图片。其它情况一律禁止转载!

推荐一个分布式单点登录框架XXL-SSO!的更多相关文章

  1. 分布式单点登录框架XXL-SSO

    <分布式单点登录框架XXL-SSO> 一.简介 1.1 概述 XXL-SSO 是一个分布式单点登录框架.只需要登录一次就可以访问所有相互信任的应用系统. 拥有"轻量级.分布式.跨 ...

  2. 深度剖析分布式单点登录框架XXL-SSO

    于2018年初,在github上创建XXL-SSO项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计-- 于2018年初,在github上创建XXL-SSO项目仓库并提交第一个 ...

  3. Hadoop生态圈-单点登录框架之CAS(Central Authentication Service)部署

    Hadoop生态圈-单点登录框架之CAS(Central Authentication Service)部署 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.CAS简介 CAS( ...

  4. [精华][推荐]CAS SSO 单点登录框架学习 环境搭建

    1.了解单点登录  SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...

  5. CAS SSO单点登录框架学习

    1.了解单点登录  SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...

  6. CAS SSO单点登录框架介绍

    1.了解单点登录  SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...

  7. 多系统实现单点登录方案:SSO 单点登录

    一.什么是单点登录SSO(Single Sign-On) SSO是一种统一认证和授权机制,指访问同一服务器不同应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后,再访问其他应用 ...

  8. 单点登录之CAS SSO从入门到精通(第三天)

    开场白 各位新年好,上海的新年好冷,冷到我手发抖. 做好准备全身心投入到新的学习和工作中去了吗?因为今天开始的教程很"变态"啊,我们要完成下面几件事: 自定义CAS SSO登录界面 ...

  9. CAS实现单点登录方案(SSO完整版)

    一.简介 1.cas是由耶鲁大学研发的单点登录服务器 2.本教材所用环境 Tomcat7.2 JDK1.7 CAS Service 版本    cas-server-3.4.8-release CAS ...

  10. 单点登录之 CAS SSO 从入门到精通(第一天)

    转自:http://blog.csdn.net/lifetragedy/article/details/43817903 啊......it's quite a long time. 好久没更新博客了 ...

随机推荐

  1. CPU cache知识 —— ARM架构cache结构和细节

    cache如何寻址 处理器访问cache时,cache电路会将CPU地址进行解码,分成3个部分,分别是: offset: 用于某个cache line -- 字抽取: index: 用于匹配某个cac ...

  2. AcWing第78场周赛

    今天想起来了,就补一下吧~ 第一题 商品分类 货架中摆放着 n 件商品,每件商品都有两个属性:名称和产地. 当且仅当两件商品的名称和产地都相同时,两件商品才视为同一种商品. 请你统计,货架中一共有多少 ...

  3. 安装mySql 出现 one more product requirements have not been satisified

    安装mySql 出现 one more product requirements have not been satisified 原因是缺少一些依赖环境. 在弹出的对话框中点击 否. 然后点击执行, ...

  4. 【云原生 • Docker】mysql、tomcat、nginx、redis 环境部署

    注意在应用部署之前,docker 服务必须是开启状态 systemctl start docker. 目录 一.MySQL 部署 二.Tomcat 部署 三.Nginx 部署 四.Redis 部署 一 ...

  5. 基于pyecharts的中医药知识图谱可视化

    基于pyecharts的中医药知识图谱可视化 关键词: pyecharts:可视化:中医药知识图谱 摘要: 数据可视化是一种直观展示数据结果和变化情况的方法,可视化有助于知识发现与应用.Neo4j数据 ...

  6. 配置 DosBox

    配置 DosBox DosBox 在高分辨的屏幕上窗口很小. 修改分辨率 Win7 及以上配置文件位于{system drive}:\Users\{username}\AppData\Local\DO ...

  7. Flask框架使用SQLAlchemy的ORM

    SQLAlchemy 1.介绍 SQLAlchemy是一个基于Python实现的ORM框架.该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用 ...

  8. 线程、GIL全局解释器锁、进程池与线程池

    目录 多进程实现TCP服务端并发 互斥锁代码实操 线程理论 创建线程的两种方式 多线程实现TCP服务端并发 线程的诸多特性 GIL全局解释器锁 验证GIL的存在 GIL与普通互斥锁 python多线程 ...

  9. 第五篇:前端之JQuery

    jQuery快速入门   jQuery jQuery介绍 jQuery是一个轻量级的.兼容多浏览器的JavaScript库. jQuery使用户能够更方便地处理HTML Document.Events ...

  10. 安装node.js与webpack创建vue2项目

    本文为博主原创,转载请注明出处: 1.安装node.js 下载地址:http://nodejs.cn/download/ (可查看历史版本) node.js 中文网:http://nodejs.cn/ ...