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

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

目录

 

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

相关文章

Jsoncpp的安装与使用方式

《Jsoncpp的安装与使用方式》JsonCpp是一个用于解析和生成JSON数据的C++库,它支持解析JSON文件或字符串到C++对象,以及将C++对象序列化回JSON格式,安装JsonCpp可以通过... 目录安装jsoncppJsoncpp的使用Value类构造函数检测保存的数据类型提取数据对json数

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧

Linux磁盘分区、格式化和挂载方式

《Linux磁盘分区、格式化和挂载方式》本文详细介绍了Linux系统中磁盘分区、格式化和挂载的基本操作步骤和命令,包括MBR和GPT分区表的区别、fdisk和gdisk命令的使用、常见的文件系统格式以... 目录一、磁盘分区表分类二、fdisk命令创建分区1、交互式的命令2、分区主分区3、创建扩展分区,然后

Linux中chmod权限设置方式

《Linux中chmod权限设置方式》本文介绍了Linux系统中文件和目录权限的设置方法,包括chmod、chown和chgrp命令的使用,以及权限模式和符号模式的详细说明,通过这些命令,用户可以灵活... 目录设置基本权限命令:chmod1、权限介绍2、chmod命令常见用法和示例3、文件权限详解4、ch

Java中的密码加密方式

《Java中的密码加密方式》文章介绍了Java中使用MD5算法对密码进行加密的方法,以及如何通过加盐和多重加密来提高密码的安全性,MD5是一种不可逆的哈希算法,适合用于存储密码,因为其输出的摘要长度固... 目录Java的密码加密方式密码加密一般的应用方式是总结Java的密码加密方式密码加密【这里采用的

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

Python pyinstaller实现图形化打包工具

《Pythonpyinstaller实现图形化打包工具》:本文主要介绍一个使用PythonPYQT5制作的关于pyinstaller打包工具,代替传统的cmd黑窗口模式打包页面,实现更快捷方便的... 目录1.简介2.运行效果3.相关源码1.简介一个使用python PYQT5制作的关于pyinstall

使用Python实现大文件切片上传及断点续传的方法

《使用Python实现大文件切片上传及断点续传的方法》本文介绍了使用Python实现大文件切片上传及断点续传的方法,包括功能模块划分(获取上传文件接口状态、临时文件夹状态信息、切片上传、切片合并)、整... 目录概要整体架构流程技术细节获取上传文件状态接口获取临时文件夹状态信息接口切片上传功能文件合并功能小