用上帝视角俯瞰单点登录的前世与今生(内含两种实现方式的源码)

本文主要是介绍用上帝视角俯瞰单点登录的前世与今生(内含两种实现方式的源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

 

1.什么是单点登录?

2.单点登录的前世与今生——前世篇(SSO)

2.1.单点登录的定义是:

2.2.总结成简单一句话说就是:

2.3.单点登录的优点:

2.4.拿去游乐园买票来讲一下单点登录的简单实现机制:

2.5.单点登录的实现机制:

2.6.单点登录的分类:

2.7.同域SSO:

2.7.1.同域SSO概念:

2.7.2.同父域SSO概念:

2.7.3.同域SSO实现流程图:

2.7.4.代码实现同域SSO:

3.单点登录的前世与今生——今生篇(CAS)

3.1.同域SSO

3.1.1.CAS

3.1.2.CAS包含两个部分:

3.1.3.在说跨域SSO流程之前要提前说几个CAS知识点:

3.1.4.理解几种票根:

3.1.5.跨域SSO实现流程图:

3.1.6.代码实现跨域SSO(基于CAS-Client):


1.什么是单点登录?

        大家都知道百度不仅仅只有搜索引擎这一个业务,它还有百度贴吧,百度云盘等众所周知的业务。而且有没有发现?你只需要在百度任意一个业务中登陆过,其他业务都默认自动登录了你这个账号呢?比如你在百度搜索中登录了你的账号,你再进入百度贴吧或者百度网盘,显示你已经登录了。

百度首页登录:

在登录这个“进阶的小名”账号的情况下,分别打开百度网盘和百度地图的效果:

       百度网盘和百度地图都默认登录了“进阶的小名”这个账号了。相对的,如果你在任何一个业务中退出登录,其他的业务也会自动退出当前账号的登录。

2.单点登录的前世与今生——前世篇(SSO)

2.1.单点登录的定义是:

       单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一退出(single sign-off)就是指,只需要单一的退出动作,就可以结束对于多个系统的访问权限。

2.2.总结成简单一句话说就是:

在多个应用系统中,用户只需要登录一次就可以访问相互信任的应用系统。

2.3.单点登录的优点:

       不管是百度还是我们自己公司的项目,随着时间的推移,我们都需要根据市场需求或是客户新的需求退出新的功能,不可能在每一个新加的模块中都写一遍登录的业务,于是单点登录解决了这个问题,将登录模块从其他业务模块中抽离出来。

2.4.拿去游乐园买票来讲一下单点登录的简单实现机制:

       我们95后的天津孩子应该都去过一个叫“乐园”的游乐场,这个游乐场里面有:“碰碰车”、“旋转木马”、“丛林鼠”、“摩天轮”等游乐设施,这么多的游乐设施,如果家长想带着熊孩子挨个儿玩一遍是不太可能了,为啥啊?还不是因为排队买票浪费时间吗!人多的时候,玩儿俩设施就家走了😂。排一个小时“碰碰车”的队,孩子进去玩10分钟出来,孩子是美了,一看,家大人又去旁边“激流勇进”排队去了,针对这种熊孩子,“乐园”就推出了通票这一制度。通票就是:“乐园”大门口买一张通票(阿姨给你手腕戴上一个印着通票盖着戳的这么一个纸圈),进到里面家大人就不用单独给熊孩子排队挨个设施买票了,家大人找个树荫下一呆,看着熊孩子带着那个纸圈满园子跑就完了😂。

2.5.单点登录的实现机制:

如下图所示,当用户第一次访问系统1的时候,因为还没有登录,会被引导到认证系统中进行登录。

  1. 根据用户提供的登录信息,认证系统进行身份效验,如果通过效验,应该返回给用户一个认证的凭据Ticket;
  2. 用户再访问其他相互信任的应用的时候,就会把这个Ticket作为自己认证的凭据,应用系统接受到请求之后会把 Ticket送到认证系统进行效验,检查 Ticket的合法性;
  3. 如果通过效验,用户就可以在不用再次登录的情况下访问系统2和系统3了。

2.6.单点登录的分类:

我将会把单点登录分为“同域SSO”和“跨域SSO”两部分说:(“跨域SSO” 会在后文 单点登录的前世与今生——今生篇(CAS)中提到)

2.7.同域SSO:

同域SSO又分为 : “同域SSO” 和 “同父域SSO”

2.7.1.同域SSO概念:

没有设置独立的 SSO 服务器,因为业务后台服务器本身就足以承担 SSO 的职能。

2.7.2.同父域SSO概念:

和同域SSO不同在于,服务器在返回 cookie 的时候,要把cookie 的 domain 设置为其父域。

2.7.3.同域SSO实现流程图:

 

同域SSO:

  1. 用户点击http://www.xiaoming.com页面登录按钮,向后台服务器发送登录请求;
  2. 输入正确的用户名密码,登录认证成功,服务器会把登录信息写入session;
  3. 服务器为该用户生成一个cookie,并加入到response header中,随着请求返回而写入浏览器中;
  4. 用户再次访问同域的http://cart.xiaoming.com的时候,浏览器会带上之前的cookie;
  5. 后台服务器通过该cookie验证当前账户的登陆状态了。

同父域SSO:

  1. 同父域 SSO 是同域 SSO 的简单升级,唯一的不同在于,服务器在返回 cookie 的时候,要把cookie 的 domain 设置为其父域。
  2. 比如两个产品的地址分别为 http://www.xiaoming.com 和 http://cart.xiaoming.com,那么 cookie 的域设置为 xiaoming.com 即可。在访问两个资源的时候,这个 cookie 都能发送到服务器,本质上和同域 SSO 没有区别。

2.7.4.代码实现同域SSO:

       接下来我通过一个Demo来演示同域SSO的要整过程。这个Demo模拟的是利用cookie实现的同域单点登录:(因为我的前后端打包部署在一个Server里,而且浏览器用同一个Origin请求前端和服务器端,即使端口号不同,也不存在跨域问题。)

      先上效果:

 

我在Hosts文件里面进行了如下配置(模拟):

127.0.0.1    www.xiaoming.com

127.0.0.1    vip.xiaoming.com

127.0.0.1    cart.xiaoming.com

127.0.0.1    login.xiaoming.com

本文只展示部分重要代码(点击获取同域SSO源码(导入项目时注意:本项目是Gradle构建的多模块项目))

登录模块后端处理登录业务代码:

@Controller
@RequestMapping("/login")
public class LoginController {//    模拟数据库用户数据public static Set<User> dbUser;static {dbUser = new HashSet<>();dbUser.add(new User(0, "zhangsan", "1"));dbUser.add(new User(1, "lisi", "2"));dbUser.add(new User(2, "wangwu", "3"));}//处理“/login”下的post请求@PostMappingpublic String doLogin(User user, HttpSession session, HttpServletResponse response) {System.out.println(dbUser);String target = (String) session.getAttribute("target");System.out.println(target);/*** 此处为lambda表达式(源码中又完整解释)*/Optional<User> first = dbUser.stream().filter(dbUser -> dbUser.getUsername().equals(user.getUsername()) &&dbUser.getPassword().equals(user.getPassword())).findFirst();//判断用户是否登录if (first.isPresent()) {//保存用户登录信息String token = UUID.randomUUID().toString();//随机生成一个token,UUID(全局唯一标识符)Cookie cookie = new Cookie("TOKEN", token);//cookie要在子系统之间互相访问,要在同一个域下cookie.setDomain("xiaoming.com");response.addCookie(cookie);//模拟缓存,把User和随机生成的cookie存(put)到“loginUser”方法中的mapLoginCacheUtil.loginUser.put(token, first.get());} else {//登陆失败session.setAttribute("msg", "用户名或密码错误");return "login";}//重定向到target地址return "redirect:" + target;}/*** 给其他子系统开放一个接口,通过token获取登录用户的信息* @param token* @return*/@GetMapping("/info")@ResponseBody//ResponseEntity <T>  ,泛型T 表示要设置的返回的 响应体public ResponseEntity<User> getUserInfo(String token) {if (!StringUtils.isEmpty(token)) {User user = LoginCacheUtil.loginUser.get(token);return ResponseEntity.ok(user);} else {//错误请求(我要token,你却没给我)return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);}}
}

 登录模块后端跳转页面控制器:

/*** 页面跳转逻辑*/
@Controller
@RequestMapping("/view")
public class ViewController {/*** 跳转到登录页面* @return* @RequestParam中 value表示参数名字  required表示是否为必需,defaultValue表示默认值* @CookieValue中 有cookie就获取“TOKEN”没有就不获取,cookie不是必须的*/@GetMapping("/login")public String tologin(@RequestParam(required = false, defaultValue = "") String target,HttpSession session,@CookieValue(required = false, value = "TOKEN") Cookie cookie) {/*** 判断target是否为空* 为空:主页面* 不为空:存到session*/if (StringUtils.isEmpty(target)) {target = "http://www.xiaoming.com:9010";}if (cookie != null) {/*** 如果是登录的用户再次访问登陆系统时,就重定向主页面(target)*/String value = cookie.getValue();//获取模拟缓存类LoginCacheUtil中拿出对应token的用户信息User user = LoginCacheUtil.loginUser.get(value);if (user != null) {return "redirect:" + target;}}
//        else {//重定向地址session.setAttribute("target", target);return "login";
//        }}
}

 首页后端跳转页面控制器:

@Controller
@RequestMapping("/view")
public class ViewController {@Autowiredprivate RestTemplate restTemplate;private final String LOGIN_INFO_ADDRESS = "http://login.xiaoming.com:9000/login/info?token=";@GetMapping("/index")public String toIndex(@CookieValue(required = false, value = "TOKEN") Cookie cookie, HttpSession session) {if (cookie != null) {String token = cookie.getValue();if (!StringUtils.isEmpty(token)) {Map result = restTemplate.getForObject(LOGIN_INFO_ADDRESS + token, Map.class);System.out.println("hahha" + result);session.setAttribute("loginUser", result);}}return "/index";}
}

文章篇幅有限,只展示部分代码,可以 点击获取同域SSO源码 clone到本地自行测试。

3.单点登录的前世与今生——今生篇(CAS)

3.1.跨域SSO

3.1.1.CAS概念:

集中式认证服务(英语:Central Authentication Service,缩写CAS)是一种针对万维网的单点登录协议。它的目的是允许一个用户访问多个应用程序,而只需向认证服务器提供一次凭证(如用户名和密码)。这样用户不仅不需在登陆web应用程序时重复认证,而且这些应用程序也无法获得密码等敏感信息。CAS 是 Yale 大学发起的一个企业级的、开源的项目,旨在为 Web 应用系统提供一种可靠的单点登录解决方法。

3.1.2.CAS包含两个部分:

CAS Server 和 CAS Client

  1. CAS Server:负责完成对用户的认证工作 , 需要独立部署。
  2. CAS Client:负责处理对客户端受保护资源的访问请求,需要对请求方进行身份认证时,重定向到 CAS Server 进行认证。

3.1.3.在说跨域SSO流程之前要提前说几个CAS知识点:

Cas-Client接口方面:

/login:登录接口,用于登录到中心服务器。

/logout:登出接口,用于从中心服务器登出。

3.1.4.理解几种票根:

1.TGT (Ticket Grangting Ticket) :

    TGT 是 CAS 为用户签发的登录票据,拥有了 TGT,用户就可以证明自己在 CAS 成功登录过。TGT 封装了 Cookie 值以及此 Cookie 值对应的用户信息。

2.TGC(Ticket Granting Cookie) :

    CAS Server 生成TGT放入自己的 Session 中,而 TGC 就是这个 Session 的唯一标识(SessionId),以 Cookie 形式放到浏览器端。

3.ST(Service Ticket) :

    ST 是 CAS 为用户签发的访问某一 service 的票据。用户访问 service 时,service 发现用户没有 ST,则要求用户去 CAS 获取 ST。

票据关系:用户信息签发TGT,TGT签发ST,PGT签发PT。

3.1.5.跨域SSO实现流程图:

 

  1. 用户访问产品 CasClientOne,域名是 http://localhost:8081
  2. 由于用户没有携带在CasClientOne上登录的 cookie,所以 CasClientOne重定向到SSO 服务器的地址。
  3. 由于用户没有携带在 SSO 服务器上登录的 TGC,所以 SSO 服务器判断用户未登录,给用户显示统一登录界面。
  4. 登录成功后,SSO 服务器构建用户在 SSO 登录的 TGT,同时返回一个 http 重定向(包含 SSO 服务器派发的 ST )。
  5. 重定向的 http response 中包含写 cookie。这个 cookie 代表用户在 SSO 中的登录状态,它的值是 TGC。
  6. 浏览器重定向到CasClientOne。此时重定向的 url 中携带着 SSO 服务器生成的 ST。根据 ST,CasClientOne向 SSO 服务器发送请求,SSO 服务器验证票据的有效性。验证成功后,CasClientOne知道用户已经在 SSO服务器登录了,于是CasClientOne构建用户登录 session。
  7. 用户访问产品CasClientTWO,域名是  http://localhost:8082
  8. 由于用户没有携带在CasClientTWO上登录的cookie,所以 CasClientTWO重定向到SSO 服务器,去询问用户在 SSO 中的登录状态。
  9. 浏览器重定向到 SSO服务器。由于已经向浏览器写入了携带 TGC 的cookie,所以此时 SSO 服务器可以拿到,根据 TGC 去查找 TGT,如果找到,就判断用户已经在SSO服务器登录过了。
  10. SSO 服务器返回一个重定向,重定向携带 ST。
  11. 浏览器带 ST 重定向到CasClientTWO。
  12. CasClientTWO根据票据向 SSO 服务器发送请求,票据验证通过后,CasClientTWO知道用户已经在SSO服务器登录了,于是生成 session,向浏览器写入CasClientTWO的 cookie。

3.1.6.代码实现跨域SSO(基于CAS-Client):

先上效果:

本文只展示部分重要代码(点击获取CAS-Demo源码(导入项目时注意:本项目是Maven构建的多模块项目))

客户端One的部分实现:

public class CasClientOne {@RequestMapping("/CasClientOne")public String CasClientOne(HttpSession session, HttpServletRequest request){Principal userPrincipal = request.getUserPrincipal();String name = userPrincipal.getName();session.setAttribute("msg",name+"登录了CasClientOne。。。");return "CasClientOne";}}

代码使用Springboot集成Cas5.3实现,点击获取配置好的Cas-Server,篇幅有限,本文中只展示了一个客户端的实现,可以 点击获取CAS-Demo源码 Clone到本地自行测试。

       关于Cas,后期还会更新一些我在公司项目中使用的(SpringBoot CAS-Client)实际遇到的一些问题的解决方案。感兴趣的小伙伴可以点点关注。觉得本文对您理解单点登录有一些帮助的小伙伴,麻烦给这篇文章点点赞。如果大佬发现本文理解存在问题,希望可以在下方评论区指点我改正。最后谢谢大家的阅读!小名祝大家每天都开开心心哒~😁

这篇关于用上帝视角俯瞰单点登录的前世与今生(内含两种实现方式的源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/871119

相关文章

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.