背景
最近开发新产品,然后老板说我们现在系统太多了,每次切换系统登录太麻烦了,能不能做个优化,同一账号互通掉。作为一个资深架构狮,老板的要求肯定要满足,安排!
一个公司产品矩阵比较丰富的时候,用户在不同系统之间来回切换,固然对产品用户体验上较差,并且增加用户密码管理成本。
也没有很好地利用内部流量进行用户打通,并且每个产品的独立体系会导致产品安全度下降。
因此实现集团产品的单点登录对用户使用体验以及效率提升有很大的帮助。那么如何实现统一认证呢?我们先了解一下传统的身份验证方式。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
传统 Session 机制及身份认证方案
Cookie 与服务器的交互
众所周知,http 是无状态的协议,因此客户每次通过浏览器访问 web。
页面,请求到服务端时,服务器都会新建线程,打开新的会话,而且服务器也不会自动维护客户的上下文信息。
比如我们现在要实现一个电商内的购物车功能,要怎么才能知道哪些购物车请求对应的是来自同一个客户的请求呢?
因此出现了 session 这个概念,session 就是一种保存上下文信息的机制,他是面向用户的,每一个 SessionID 对应着一个用户,并且保存在服务端中。
session 主要以 cookie 或 URL 重写为基础的来实现的,默认使用 cookie 来实现,系统会创造一个名为 JSESSIONID 的变量输出到 cookie 中。
JSESSIONID 是存储于浏览器内存中的,并不是写到硬盘上的,如果我们把浏览器的cookie 禁止,则 web 服务器会采用 URL 重写的方式传递 Sessionid,我们就可以在地址栏看到 sessionid=KWJHUG6JJM65HS2K6 之类的字符串。
通常 JSESSIONID 是不能跨窗口使用的,当你新开了一个浏览器窗口进入相同页面时,系统会赋予你一个新的 sessionid,这样我们信息共享的目的就达不到了。
服务器端的 session 的机制
当服务端收到客户端的请求时候,首先判断请求里是否包含了 JSESSIONID 的 sessionId,如果存在说明已经创建过了,直接从内存中拿出来使用,如果查询不到,说明是无效的。
如果客户请求不包含 sessionid,则为此客户创建一个 session 并且生成一个与此 session 相关联的 sessionid,这个 sessionid 将在本次响应中返回给客户端保存。
对每次 http 请求,都经历以下步骤处理:
- 服务端首先查找对应的 cookie 的值(sessionid)。
- 根据 sessionid,从服务器端 session 存储中获取对应 id 的 session 数据,进行返回。
- 如果找不到 sessionid,服务器端就创建 session,生成 sessionid 对应的 cookie,写入到响应头中。
session 是由服务端生成的,并且以散列表的形式保存在内存中。
基于 session 的身份认证流程
基于 seesion 的身份认证主要流程如下:
因为 http 请求是无状态请求,所以在 Web 领域,大部分都是通过这种方式解决。但是这么做有什么问题呢?我们接着看。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
集群环境下的 Session 困境及解决方案
随着技术的发展,用户流量增大,单个服务器已经不能满足系统的需要了,分布式架构开始流行。
通常都会把系统部署在多台服务器上,通过负载均衡把请求分发到其中的一台服务器上,这样很可能同一个用户的请求被分发到不同的服务器上。
因为 session 是保存在服务器上的,那么很有可能第一次请求访问的 A 服务器,创建了 session,但是第二次访问到了 B 服务器,这时就会出现取不到 session 的情况。
我们知道,Session 一般是用来存会话全局的用户信息(不仅仅是登陆方面的问题),用来简化/加速后续的业务请求。
传统的 session 由服务器端生成并存储,当应用进行分布式集群部署的时候,如何保证不同服务器上 session 信息能够共享呢?
Session 共享方案
Session 共享一般有两种思路:
- session 复制
- session 集中存储
①session 复制
session 复制即将不同服务器上 session 数据进行复制,用户登录,修改,注销时,将 session 信息同时也复制到其他机器上面去。
这种实现的问题就是实现成本高,维护难度大,并且会存在延迟登问题。
②session 集中存储
集中存储就是将获取 session 单独放在一个服务中进行存储,所有获取 session 的统一来这个服务中去取。
这样就避免了同步和维护多套 session 的问题。一般我们都是使用 redis 进行集中式存储 session。
多服务下的登陆困境及 SSO 方案
SSO 的产生背景
如果企业做大了之后,一般都有很多的业务支持系统为其提供相应的管理和 IT 服务,按照传统的验证方式访问多系统,每个单独的系统都会有自己的安全体系和身份认证系统。
进入每个系统都需要进行登录,获取 session,再通过 session 访问对应系统资源。
这样的局面不仅给管理上带来了很大的困难,对客户来说也极不友好,那么如何让客户只需登陆一次,就可以进入多个系统,而不需要重新登录呢?
“单点登录”就是专为解决此类问题的。其大致思想流程如下:通过一个 ticket 进行串接各系统间的用户信息。