CAS 分为两部分,分别是 CAS Client(中间登录客户端)和 CAS Server(登录处理服务器)。在现实生活中还是挺多使用到 CAS 的,例如淘宝和天猫网站便是,未登录情况下,无论在淘宝上还是在天猫上点击登录都会跳去相同的登录页面,而这个登录页面其实就是 CAS Client。当登录成功后,会发现无论是在天猫还是淘宝都会是登录状态。
回到a.test.com网站后,将参数 ticket 传递给服务端,服务端会将 ticket 拿到 CAS Server 进行验证,验证通过后便会返回登录成功。
用户第一次访问c.haha.com后,点击登录同样会重定向到 CAS Server 中,这时候由于上一次已经在 CAS Client 客户端的 Cookie 中存储了 ST,所以 CAS Server 会发现请求头部已经带上了上一次登录的 ST,这时候便会直接同定向回c.haha.com中,并且带上参数ticket。
如果做过大型网站的童鞋们,相信对单点登录肯定不陌生。就好比如天猫和淘宝,当我在淘宝处成功登录之后,再跳去天猫网站,你会发现,在天猫处也会神奇滴登录了。🤔
为什么会这样?没错,就是今天的主角——单点登录的“锅”。
毫无疑问,对于一个拥有多套子系统的公司来说,单点登录是必须实现的,它不仅可以减少开发者对于各个子系统对应的登录功能维护,还能更好滴提升用户体验。
那么问题来了,对于一个单点登录(SSO)的功能实现,可以从哪方面思考呢?下面我们就来一起探讨一下啦...
目录
传统登录和JWT
在讲解之前,我觉得是很有必要提提登录的基本实现的。就好比如,如果我要让你实现一个登录功能,你会如何实现呢?
相信很多童鞋都会知道使用 Session 和 Cookie 实现,那么还有吗?哈哈,相信你也能看到,就是时下最为常用方式 JWT。那么问题来了,它们之间有什么区别?甭急,下面将会简单讲解一下。
传统登录的实现其实就是使用 Session 和 Cookie 的,那先看看它们的处理流程是怎样。
利用 Session 和 Cookie 技术实现的传统登录功能,过程并不难理解,简单滴说,就是服务端负责管理用户状态和验证,而客户端则负责存储用户状态。
那么问题来了,服务端返回的 SessionId 一定是要使用 Cookie 存储吗?还是说可以存储在 SessionStorage 或者 LocalStorange 上?🤔
对于这个问题,其实也是我一直思考的,定性思考一番,其实也是有它的目的。首先可以明确的是,服务端返回的 SessionId 不一定要使用 Cookie 进行存储的,可以使用诸如 SessionStorage、LocalStorage 等方式进行存储的。
那么使用 Cookie 存储服务端返回的 SessionID 有什么好处?主要是为了减轻前端开发者负担,由于服务端可以直接通过设置返回头 Set-Cookie 来直接在客户端的 Cookie 中存储 SessionId。这样一来,客户端就可以免去了手动保存 SessionId 的步骤,直接处理相应登录业务逻辑即可。
虽然使用 Cookie 可以很方便开发者的存储相应的用户状态,但是却会导致诸如 XSS、 CSRF 等安全性问题。
使用 Session 和 Cookie 技术实现的登录功能依然存在着缺陷。
首先就是 Cookie 允许被用户禁止,当一个浏览器禁止使用 Cookie 后,那么服务器中存储的 Session 也被禁止,直接导致相应的用户无法进行登录。另外,当用户访问量很大时,对服务器的压力也会大,因为用户访问量大将会触使服务器需要管理大量用户的 Session,想象一下,访问量达到亿级别时会怎样?毫无疑问,服务器管理的 Session 越多,对服务器本身压力也会大。
那么,有没有一种方式可以克服以上的缺陷呢?有~那便是 JWT。
JWT 是 Json Web Token 的缩写,一个规范用于用户和服务器之间传递安全可靠的信息。(简单滴说,就是所谓的 Token 机制)。让我们先看看 Token 机制的处理流程。
Token 机制相对于传统登录方式的最大区别就是,所有的用户状态都交给客户端进行管理和存储。
Token 可以看成是一张门票,当你想去看演唱会时,那必须得先展示门票。
一个 JWT 实际上就是一串字符串,由三部分组成,分别是
Token 机制由于无需在服务端管理用户状态,因此极大滴减轻了服务器的压力,另一方面,由于在登录后的任何请求,都不会再在请求中带上用户标识,这样一来,就可以极大滴避免 CSRF 攻击。
如何实现单点登录?
在大型网站下,实现单点登录变得越来越重要,那么要实现单点登录具体有哪些方案呢?
要实现单点登录,个人总结认为,主要有 Session 共享机制、Cookie 跨域处理、CAS 服务 三种方案。(当然可能还有其他方案,欢迎各位大佬们来分享分享啦 😄)。那么我们就来简单分析一下。
Session 共享的实现,大部分工作都是需要后端配合的,一般涉及到集群方面等,当然如果使用的是 Node的话,可以使用 Redis 实现,将所有的 Session 都放在中间层管理。
下面就讲讲 Cookie 跨域处理和 CAS 服务两种方案,这两种方案也是前端开发者常常需要考虑的方案啦。
如果你使用过 Cookie 的话,肯定会知道 Domain 。那么 Domain 究竟是拿来干嘛的?
Cookie 中 Domain 就是拿来约束使用 Cookie 的域名管理。举个例子,如果网站
a.test.com
和b.test.com
是可以通过 Cookie 进行通信的,因为 Domain 会被设置为test.com
,相反如果网站a.test.com
和c.haha.com
就无法通过 Cookie 进行通信,因为网站c.haha.com
无法受到 Domain 限制而无法获取相应的 Cookie 值。先回顾一下跨域的同源政策,只有同协议、同域名、同端口才符合同源政策。
那么在跨域情况下,需要如何让 Cookie 进行通信呢?
当用户在网站
a.test.com
进行登录,后端根据用户名和密码判断该用户是网站c.haha.com
中用户,会先在a.test.com
登录后再返回标识给客户端。客户端先配置好 axios 的请求头部字段
withCredentials
为 true。同时,运维需要在 Ngix 中配置接口允许 CORS,并且设置相应的响应头部字段。
必须要注意的是,CORS 在允许跨域处理 Cookie 时绝对不能设置 access-control-allow-origin 值为 *,只能针对性的域名。
客户端根据标识调用相应网站的登录接口(如
c.haha.com/ligon
)去登录,登录成功后,后端会在c.haha.com
的 Cookie 中存储 Token 值(此时还是在网站a.test.com
中),这时候就可以跳转到c.haha.com
主页。去到
c.haha.com
主页后,获取相应 Cookie 中 Token 值配置在请求头部字段 authorization中,便可实现单点登录功能。在上面的基本流程中,相信你肯定会有问题,甭急,让我们一个个来解决。
在 axios 的请求头部字段设置
withCredentials
的值为 true 有何用?其实,
withCredentials
字段用于允许跨域处理 Cookie。但是单纯配置它是没法起效果的,必须要结合运维在响应头部加上 access-control-allow-credentials 和 access-control-allow-origin 两个字段才能起效果。既然在 CORS 中的 access-control-allow-origin 响应字段必须为针对性的域名而不能设置为 *,那么在本地开发时,如何配置?
要处理这个问题,有两种方案,一种是在 access-control-allow-origin 响应字段中增添一个域名为 localhost。另一种则是配置 webpack-dev-server 中 proxy,如下:
时下,使用 Cookie 跨域处理是改动最小方案,也是目前最优的选择方案。
CAS 服务,相当于所有的网站的登录服务,都统一使用一个登录网站处理。
CAS 分为两部分,分别是 CAS Client(中间登录客户端)和 CAS Server(登录处理服务器)。在现实生活中还是挺多使用到 CAS 的,例如淘宝和天猫网站便是,未登录情况下,无论在淘宝上还是在天猫上点击登录都会跳去相同的登录页面,而这个登录页面其实就是 CAS Client。当登录成功后,会发现无论是在天猫还是淘宝都会是登录状态。
在了解 CAS 服务前,需提前了解以下几个知识点。
TCT(Ticket Granting ticket 缩写)
可比作是一个 Session,CAS Server 会根据用户名和密码生成一个 TGT。
TGC(Ticket-granting cookie 缩写)
其实就是一个 Cookie,用于存放用户身份信息。
ST(Service ticket 缩写)
可简单比作是一个 SessionId,一次性票据,用于验证用的,只能用一次,可以想象成服务端发送给客户端的一张门票。
接下来,我们就来瞅瞅,CAS 服务的流程是如何的。
用户第一次访问
a.test.com
网站时,点击登录会重定向到 CAS Server,发现请求中没有 Cookie,那么便会返回状态 302,重定向到 CAS Client 登录页面。在 CAS Client 中输入用户名和密码并且点击提交后,CAS Server便会生成一个 TGT,再用 TGT 生成一个 ST,然后便会在返回头中 Set-Cookie ,在客户端 Cookie 中存储 ST。
存储成功后,便重新回到上面的 previosurl 中,并带上一个 ticket 参数(用于后端验证用的)。
ticket 后面的值就是 ST。
回到
a.test.com
网站后,将参数 ticket 传递给服务端,服务端会将 ticket 拿到 CAS Server 进行验证,验证通过后便会返回登录成功。用户第一次访问
c.haha.com
后,点击登录同样会重定向到 CAS Server 中,这时候由于上一次已经在 CAS Client 客户端的 Cookie 中存储了 ST,所以 CAS Server 会发现请求头部已经带上了上一次登录的 ST,这时候便会直接同定向回c.haha.com
中,并且带上参数ticket
。回到
c.haha.com
后,同样会拿 ticket 传递到服务端,服务端拿到 ticket 后便会再次拿到 CAS Server 中进行验证,验证通过便会成功登录。至此,一个单点登录功能便实现。可以看到的是,CAS 服务原理就是利用中间客户端 CAS Client 复用 Cookie 值实现单点登录功能。