2013-12-14 简单了解单点登录(SSO)的两种模式

什么是单点登录

单点登录-Single Sign On,简称SSO,是目前比较流行的企业业务整合的解决方案之一。

简单来说就是用户只需要登录一次就可以访问所有的相互信任的应用系统

单点登录的实现模式有很多,有一些是标准的模式,比方说CAS(Central Authentication Service)、OAuth2;还有一些是非标准的,一个公司一个样,一般来说,大公司会用标准的方式,而小公司会考虑成本的而选择非标准的

但是最终到了技术层面的实现就以下两种方式:

  • session+cookie
  • token

为什么需要单点登录

首先有些公司可能会有多条产品线,比如公司做了一个小游戏,又做了一个商城,还有一些其他的产品等,现在希望这些子系统之间共享同一套用户系统,这时候就需要把用户系统抽离出去,于是就形成了认证中心

这里就涉及了一个问题,就是如何在认证中心进行认证,认证之后又如何通过这个认证的结果,畅通的去访问子系统,这里就产生了很多种模式

Session+Cookie模式

013-12-14

如上图所示,这种模式下:

  • 第1步,在认证中心登录
  • 第2步,用户中心判断用户的账号密码没问题之后会记录一个session存在服务器的数据库中,其实就是一条一条的键值对,值是用户身份信息,键是唯一的id,此时,只要在这个表格里面记录了这个键值对,则表示用户登录成功了,反之用户登录失败(一种压根没有登录,二种就是登录过期了)
  • 第3步,就是返回一个sid,通过cookie方式,保存到客户端
  • 第4步,下次请求会带上这个cookie,就是这个sessionId去访问子系统
  • 第5步,子系统会带着sid向认证中心询问,这时候认证中心会根据这个sid去数据库表格里查找
  • 第6步,认证中心查到了则表示sid是有效的
  • 第7步,子系统返回有效的受保护的资源

好处

服务器有超强的用户控制能力,比如哪一天让用户下线,只要把数据库里的sid删除掉就可以了,不用去改什么cookie,只要数据库里没有当前用户的sid,则只能重新登录

缺点

最大的缺点就是耗钱,而且是超级耗钱,用这种模式服务器的数据库表格的用户量可能会变的非常大,如果有1亿用户,则表格中就有1亿条记录,对于小企业根本承受不了;而且一旦认证中心挂掉,,那所有的子系统全部完犊子,所以认证中心要做很强的防护,还要做容灾,全都是钱,子系统扩容,认证中心就要扩容,全是钱

Token模式

013-12-14

如上图所示:

  • 第1步,还是登录,到认证中心登录,这个时候认证中心即服务器不存取session,也就是不存储任何东西
  • 第2步,认证中心会返回一个token,这个token一般就是JWT(JSON Web Token)-数字签名,一个不可被篡改的字符串,然后让客户端自己去保存,存在cookie也可以,存在localStorage也可以,无所谓,移动端都可以存在本地,有这个token表示已经登录成功了,会有失效日期
  • 第3步,后续访问子系统就需要带上这个token,子系统可以验证这个token的
  • 第4步,子系统验证token,不需要去询问认证中心,这里会有一些机制,比如子系统与认证中心之间会相互去沟通一个秘钥,这里了解不多,总之子系统能够自行验证,认证中心压力减小,验证有效返回有效资源,无效重新登录

好处

认证中心压力减小,子系统扩容跟认证中心没啥关系,因为子系统不会与认证中心产生请求,所以token这种模式是一种分布式的认证机制,每个子系统自行去认证

坏处

很难进行集中控制,比如有一个用户天天捣乱,我想让他下线,那你很难下线的,因为认证这个token的工作是由子系统来做的,要让他下线,只能去通知每个子系统让其去拦截,加入黑名单,不让登录,很麻烦

在上述麻烦下,想让认证中心有一定的控制能力,这时候就产生了双token模式

刷新Token模式

013-12-14

013-12-14

如上两图所示,子系统登录后会从认证中心拿到两个token,第一个是正常的token,过期时间较短,一般半个小时,另外一个token就是refresh token,过期时间比较长,一般一周左右,这时候正常子系统去拿token去访问资源,一旦失败就出现第二张图所示情况了

用户显然不希望每隔半小时就重新登录,这时候就需要刷新token即refresh token了

  • 第1步,用户根据token去访问子系统,结果失效了
  • 第2步,失效后,这个长期有效的刷新token就起作用了,这个刷新token只能在认证中心认识,其他系统不认识
  • 第3步,用户根据这个刷新token去向认证中心请求,认证中心发现这个刷新token还是有效的,结果返回一个新的token
  • 第4步,得到新的token,在去请求失效接口重新访问子系统

这里刷新token的作用是让用户每隔一小段时间来一次认证中心,来一次的目的是便于控制,如有一天想让某个用户下线,虽然没有办法让他立即下线,但是他半小时(在token失效下)会来一次认证中心换新的token,这时候就可以不给换新的token,就达到了下线的目的了,这种实效性虽然没有session那么强,但是总归聊胜于无吧,本人目前所在的公司就是使用了这种刷新token的模式

补充JWT(JSON Web Token)

JWT本质上就是一个字符串,只不过这个字符串是通过特殊方法进行过加密特殊处理的,而且刚好可以用来Web应用里的一些问题

013-12-14

上图是没有JWT的情况,往往浏览器请求服务器后,会得到一个用户信息让浏览器记住,以便下次再请求时带上这个信息,服务器能够认识。但是服务器是无法信任这个信息,因为这个信息存在客户端是极其容易被伪造的,比如存在cookie里面或localStorage,这些都可以改,所以服务器无法识别与信任,这到底是以前发给其的信息还是已经更改过的信息,还是压根就没有登录过的信息

过去呢,用session+cookie的方式可以解决这个问题,比如说服务器存储一个session,然后把对应的sessionID编号发给浏览器,下一次浏览器把这个编号id发过来,服务器又在自己内存里面去找或者数据库里去找看下有没有对应的session,但是这种做法会导致服务器会有非常大的存储压力,它要存很多很多的session,所以归根结底啊,都是因为服务器无法信任导致的,也就意味必须要找到一种办法能够让服务器信任这个信息

这个办法就是JWT模式,如下图所示

013-12-14

对服务器返回的信息info+密钥通过一个算法生成一个签名,在把这个签名和信息info一起发送给浏览器,下次浏览器请求的时候会带上这个信息到服务器,服务器会把这个信息取出来,用相同的密钥在解密生成一个签名与浏览器的签名进行对比验证

这个签名里面暗含了两个信息:一个是原始信息info,另外一个是服务器的密钥,只要保证这两个信息不变,则就可以防止伪造,这样服务器就可以信任这个信息了,完美的解决了问题

在node中示例:

const crypto = require("crypto");

function sign(info, key) {
  return crypto.createHmac("sha256", key).update(info).digest("hex");
}

console.log(sign("abc", "123"));  // 8f16771f9f8851b26f4d460fa17de93e2711c7e51337cb8a608a0f81e1c1b6ae

因此,有了JWT之后,服务器就不再需要使用session模式了,不需要在去开辟任何的存储空间

当然JWT除了上述info+签名之外还加入了其他信息组合而成的如下:

013-12-14

整个JWT就是三个部分的字符串连在一起,字符串与字符串之间使用一个点符号进行分割

  • header,其实就是一个JSON格式的对象,经过base64编码形成了字符串,这个对象里面记录了两个东西,一个是签名算法,另一个是标记整个字符串的类型是JWT,经过base64之后形成一个完整的字符串

013-12-14

  • payload,也就是主体内容,身份信息等和header一样
  • sinature,将前面两个加起来,给一个密钥,使用相应的加密算法得到一个签名结果,再把这个签名经过base64得到signature

原文链接:https://juejin.cn/post/7312387695463809036 作者:xumaozeng

(0)
上一篇 2023年12月15日 下午4:06
下一篇 2023年12月15日 下午4:16

相关推荐

发表回复

登录后才能评论