博主在前段时间参与开发了公司内部的统一登陆认证平台,于是,便有了这篇文章。
一、为何要开发这个东西?
现状:
- 各系统都有自己的登陆页
- 各系统单独维护自己一套登陆体系,使用方需要记住多套账号密码
- 各系统都有自己的UI ,布局不统一
- 使用成本高,多个系统都有属于自己的权限控制,对新人不友好,授权入口也不统一
- …
总之,很麻烦很麻烦。
于是为了解决这些问题,统一登陆认证平台势在必得。
二、相关概念
为了更好的理解这篇文章,我们首先需要先了解一些相关的概念。
- sso
sso 是英文 Single Sign On 的缩写,翻译过来就是单点登录。举个例子,当同个公司有多套内部系统时,只要你登陆其中一个系统,其他的系统都可以直接跳转,免重新登陆,就好比说你买了游乐园的套票,有了这一张套票,就可以玩遍游乐园所有的设施,不用每个设施单独买票,大大优化了用户体验。
- cas
sso 只是一个架构设计,而 cas 则是实现这种架构的其中一种实践方式。
CAS 是 Central Authentication Service 的缩写 —— 中央认证服务,一种独立开放指令协议,是 Yale 大学发起的一个企业级开源项目,旨在为 Web 应用系统提供一种可靠的 SSO 解决方案。
三、系统演进方式
我们先看看传统的登陆体系设计
3.1 多系统隔离设计
这是最为简单的登陆体系模式,每个系统都是单独设计的,登陆态也是进行单独的维护。
- 优点:设计简单,每个系统独立,资源隔离,互不影响
- 缺点:开发成本高,每个系统都要单独搞登陆体系,运维成本高
3.2 多系统共享登陆态机制
所谓的共享登陆态,就是想办法让多个系统公用一份登陆态,例如基于 cookie 同域的机制,让同个二级域名下的多个站点共享cookie来达到跨域名访问的情况。
只要登陆态的存储机制是独立的。
优点:简单实现了单点登陆
缺点:有一定限制,例如需要同一个域下
3.3 基于CAS 的登陆体系设计
我们在原多系统的上一层抽象出了一个中央鉴权服务,用户只要在 CAS 上登陆,就可以免重新登陆进入所有接入的相关系统。
我们简单放一下具体的时序图。
在这里我们进行一定的解释。
- 用户进行登陆某个具体的系统,系统发现其未登录,直接重定向到 cas 的登陆页面中。
- 用户在CAS登陆页面中进行登陆,CAS后端生成该用户的登陆态,并返回其登陆标志 session_id
- CAS 前端设置cookie,并根据 session_id + 注册系统的唯一标识获取有效期内的ticket
- CAS 前端拿到cookie 后携带cookie 重定向位系统注册时的回调地址(一般是登陆接口)
- 注册系统通过ticket 向CAS服务获取 session_id
- 注册系统通过session_id 向 CAS 服务获取用户信息
- 注册系统通过拿到的用户信息进行本地系统登陆态缓存
四、需要提供的相关能力
接下来我们大概了解一下实现这么一个机制需要提供哪些具体的能力。
举个例子,假设目前我们有两个系统,两个系统都是有自己的登陆体系的。
我们礼貌的称之为 A 系统, B 系统。
4.1 实现统一账号体系
这是一个比较大的前提条件。
如果每个系统都有自己的用户体系,打通他们便是一个十分重要的事情,不然怎么一套用户密码去使用多个系统呢。
假设 A,B 两个系统均有自己的用户数据。那么我们应该先对用户进行打通。
楼主有幸在实习阶段就做了类似的项目,其实对用户中心服务来说,只要实现唯一的用户体系即可,其他系统接入时可在原有的用户表增加用户中心ID标识来标志身份。关于怎么确认一个用户的唯一维度,这个需要基于已有的接入方来进行考虑,例如:
- 身份证唯一
- 手机号唯一
- 登陆账号唯一
又或者是其中的优先级搭配。这个需要具体业务具体分析。
而楼主接触过的两种,一种是基于手机号+身份证的(因为游戏需要实名验证并且绑定手机号),另一种而是基于登陆账号唯一的(内部集团账号)
当然统一用户体系并不是这篇文章的重点,因此我们在此止步,想要了解的童鞋可以自行查阅相关的资料
4.2 实现统一的登陆验证
既然有了统一的账号体系,那么需要提供统一的登陆验证能力。这个能力的提供按照业务划分应该是属于用户中心的范畴,不该归属于 CAS 服务。实际上就是对账号密码的验证。例如集团账号的登陆验证,因为不可能将集团账号的密码提供给各个子公司,因此集团部门会单独提供密码验证的服务开放给各个子公司。
4.3 CAS服务需要提供的能力
必要能力:
- 是否登陆接口(对外)
- 登陆接口(内部)
- 根据session_id + 应用注册code 获取临时凭证 ticket (对外)
- 通过 ticket 获取 session_id (对外)
- 通过 session_id 获取用户信息(对外)
- 退出登陆接口(内外)
- 登陆退出事件发布
额外能力:
- 应用注册能力:提供应用的注册,应用相关的配置
- 登陆日志:应用的登陆日志,登陆来源,登陆IP等
- …
4.4 额外的单点登出能力
本质上,CAS 是统一的授权服务,并不要求单点登出。
单点登陆能力应该作为可选操作。
主要是有两种实现方式。
- 嵌入式系统
由于我们需要提供CAS的前台系统(提供注册应用、配置应用、查看登陆日志等功能),因此可以通过嵌入进 CAS前台 的方式实现同域的登陆态共享 (微前端模型),当系统登陆态失效时,由于同域cookie被删除,因此直接实现了单点登出
- 非嵌入式系统
对于独立性较强的系统。我们可以通过生产-消费者模型来异步通知。有几种实现的方案。
- 基于消息队列(RocketMQ版)模型的订阅发布
- 自定义通知器,由各个系统提供单独的退出接口,当某个系统退出时,调用CAS 的退出接口,CAS 再去异步的调用各个系统注册的退出接口
目前,我们采取的是基于阿里云的消息队列模型,CAS 发布退出事件,各个应用系统进行事件的订阅,并自行处理退出事件。
本质上,并无太大差别,主要还是阿里的东西,不愁钱用的香。
五、一些设计上的考虑
- CAS 相关的接口能力应该考虑到高并发,高可用
- CAS 相关的接口应该考虑鉴权操作
- 非嵌入式的系统,在登陆后,应该保留自己的一份本地登陆态,并且登陆态的有效期应该低于 CAS 的登陆态有效期,当本地登陆态失效时,应尝试访问CAS 的是否登陆接口,如果确认仍在登陆,应该自动续权登陆
- CAS 的登陆态应该提供有效期刷新机制,建议在是否登陆接口上补充刷新机制,例如每次调用直接重置计时时间
- 为了保证单用户的唯一登陆,在已登陆情况下重新登陆,应该将原有的登陆态清除后再重新登陆
- 相关的cookie 应该设置为 http only
- 相关的浏览器私密数据建议使用加密算法进行存储,避免用户直接修改cookie的内容达到一些风险操作。
- …