有关登录的那些事

1,449

作者:李嘉豪 lijiahao043@ke.com

这篇文章的主题是互联网公司和登录相关的那些技术栈,分为 3 个部分。单点登录,Oauth2.0 和 扫码登录。虽然不能涵盖所有的登录体系,但是掌握了这三种登录技术,理解其他和登录有关的技术体系,对你而言绝非难事。

单点登录

单点登录的意义

互联网公司也是近几年才有的概念,十几年前,一个公司,一台服务器,一个域名是常有的事。但现在,一个公司有多个部门,多个业务线,每一个部门都有独立的服务,每一套服务对应一个域名。对于公司而言,每一个部门不想花时间单独搞一套登陆系统;对于个人而言,我登录了你司的 a 服务,我不想再在使用 b 服务的时候,再登陆一次。 于是,单点登录应运而生。

如何设计单点登录

假如公司让你设计一套登录系统,下面这套设计方案只会让用户抓狂。

1.png

2.png

所以,下面的情形中,换做你来登录设计,你如何设计呢?‘

3.png

单点登录的两大方式

基于 cookie 共享的单点登录系统

image.png

  1. 访问 a.ke.com,检查到没有登录态(token)
  2. my-login.ke.com?redirectUrl=a.ke.com
  3. 登陆成功后,二级域名也就是,ke.com 域下注入 token
  4. b.ke.com 如果再登陆,发现有 token,发送异步请求验证 token,有效,返回 html 字符串,也就是 b.ke.com 的主页面。

但是,这种单点登录方式有什么问题?

image.png

随着企业规模的扩大,业务的拓张,二级域名有可能并不相同,此时再用基于 cookie 共享的单点登录会无效。

**把 token 拼到重定向 url 上的方案

image.png

  1. 登录 a.ke.com,发现没有登录态(token)
  2. my-login.ke.com?redirectUrl=a.ke.com
  3. my-login.ke.com 域下注入 token
  4. a.ke.com?token=xxx
  5. a.ke.com 域下注入 token
  6. b.lianjia.com
  7. my-login.ke.com 下已有 token
  8. b.lianjia.com?token=xxx
  9. b.lianjia.com 下注入 token

单点登录 demo

为了方便读者深刻地体会单点登录原理,作者提供了一个单点登录的小 demo,个人非常建议读者把这个 demo git clone 下来跑一跑,这比只看文章形成的理解要深刻的多。

demo 技术栈

  1. 原生 nodejs
    •   post 的参数
    •   set-cookie domain
    •   form type=’hidden’
  2. ejs 模板引擎
    •   ssr 服务端渲染 我稍微展开一下 demo 里面比较值得说的几个点。post 请求获取参数的过程并非一次性获得的,而是需要多次获得参数 chunk,并把它们合并起来,这是因为服务器端不知道请求参数的多少( post 参数不像 get 参数那样有上限,参数量有可能非常大);另外一点是 set-cookie 的 domain 的字段,这个字段告诉了浏览器,服务端想注入的 cookie 只在哪个域名下是有效果的。另外一个知识点是 type='hidden' 这个属性的含义,这种方式可以以一种对用户透明的方式把相关参数传给服务端。

这个小 demo 也用到了服务端渲染的相关知识。这里简单介绍一下客户端渲染和服务端渲染的区别,客户端渲染指的是第一次从服务端拿 html,html 里面是没有数据的,当 js 加载以后,js 里会发异步请求获得数据,再更新 html。服务端渲染指的是服务器会直接返回具有数据的 html。

链接

  1. github.com/Ethan199412…

OAuth 2.0 原理

OAuth 2.0 的意义

先给大家展示两个典型用到了 OAuth 2.0 的场景:

image.png

image.png

请大家带入想一想下面这个情形:

我是一个小公司叫 B+,我要用贝壳的房源信息,在这个基础上对数据进行一定的分析和加工,那么我需要用户登录贝壳,调用贝壳一些开放 api 以获取用户的数据,但是用户一定不希望我直接获得他在贝壳上面的用户名和密码。

这个时候我们就需要使用 Oauth。

第一方,第二方和第三方之争

首先问大家两个问题。

在 B+ 的那个例子里面,请问谁是第三方?

在豆瓣的那个例子里面,请问谁是第三方?

其实网上并没有一个官方的说法能把第一方,第二方和第三方讲的很清楚。一般而言,第三方指的是用别人数据的那个应用。所以,如果我们用 B+ 登录贝壳获取贝壳的数据时,第三方指的是 B+。而在豆瓣微信登录的那个例子里,豆瓣需要登录微信获取用户信息,按照上面的定义,似乎豆瓣才是第三方吧,但对于豆瓣而言,你可以说用微信登录是第三方登录。所以大家这块不要混淆,在 oauth 标准里谁是第三方,和用第三方登录是两个概念。

OAuth 2.0 的原理

回到我们第一个例子,大家想一想能否这样设计,假如你是贝壳负责第三方登录这块的人,你让 B+ 的开发者在自己的登录页面上直接输入用户名和密码,B+ 的服务直接把用户名和密码传过来以作为用户凭证获取贝壳的数据?

image.png

答案一定是否定的,因为对于客户而言,他的贝壳用户名和密码等于直接给了 B+,假如 B+ 把贝壳的用户名和密码记录了下来,那么用户信息很容易被泄露甚至交易。

所以说,我们需要一种手段,这种手段既可以让第一方有获取第三方数据的凭证,同时又不直接获取用户的用户名和密码。这种手段就是 OAuth2.0

简易版 OAuth 2.0

image.png

  1. 用户访问 www.b-plus.com,点击登录贝壳
  2. login.beike.com?redirectUrl=www.b-plus.com
  3. www.b-plus.com?token=xxx

至此,用户在想获取微信数据的时候,就不需要再登录了,同时,也不需要用户名和密码。但是,由于 token 是放在 url 上的,它并不安全,假如在传输过程中有人把这个 token 截获到,它依然可以用它获取贝壳的用户信息。

oauth 2.0 授权码模式

image.png

  1. 用户访问 www.b-plus.com
  2. login.beike.com?redirectUrl=www.b-plus.com
  3. www.b-plus.com?code=xxx
  4. 服务获得 code,服务发送 ajax 请求获取 token,code 是单次有效的,只有第一个人才能用 code 换取 token

基于授权码模式的 oauth2.0 是目前最成熟也是最常用的一种 oauth 鉴权模式。

OAuth 2.0 申请认证要提供什么

  • response_type: 授权类型,对于授权码模式的 oauth,写 code
  • client_id: 客户端 id,用来作为第三方应用的唯一标识符
  • redirect_url: 认证服务器往哪里传 code,传 token
  • scope: 都申请哪些权限,如果不写,则申请默认权限

关键概念

在学习 OAuth 2.0 中,如下这几个概念非常重要。

  • Third Party Application: 想要获取别人数据的那个 (B+)
  • Resource Owner: 拥有用户信息的那个人 (使用者)
  • Authorization Server: 授权服务器,例子里为贝壳的授权服务器
  • Resource Server: 资源服务器,贝壳提供数据和接口的地方

redirectUrl 的第二个作用

显然,重定向 url 的第一个作用非常好理解,这个是第三方获取认证服务器提供 code 和 token 的地方。但是它其实有第二层意义,那就是认证服务器会根据它是否一致判断拿 code 的请求和拿 token 的请求是否是同一个人发过来的,如果是一致的,那么给 token,如果不一致,就不给 token。

假如用户是第一次获取到 token,那么重定向 url 被认证服务器至少知晓了几次?重定向 url 被认证服务器比对了几次?

知晓三次,第一次,用户在认证服务器上注册第三方资料的要填写一次;第二次,认证服务器获得申请 code 请求的时候要取出参数中的重定向 url,和注册的重定向 url 进行比对;第三次,认证服务器获得申请 token 的请求时要取出参数中的重定向 url,和申请 code 时的重定向 url 进行比对。因此,答案是知晓三次,比对两次。

AccessToken 和 RefreshToken

这两个 token 其实非常好理解,accessToken 作为从数据服务器上拿数据的唯一凭证,它注定是要放在每一次请求里的,大家想一下,既然频繁交互于网络,那么它相对而言风险也更高。假设这个 accessToken 的存活时长是无限的话,这就代表一旦被黑客获取,获得 accessToken 与获得用户名和密码是等效的。所以,accessToken 的特性之一是,具有严格的时效性,一旦过期,accessToken 不再被认证服务器承认。但是频繁的登录又会影响用户体验,所以,第三方会用一直放在本地的 refreshToken 再去获得一个崭新的 accessToken。整个过程对用户透明。

帮助你记忆 Oauth2.0 原理的一张图片

Oauth 2.0 的用户名和密码有点像我们高中化学学的置换反应,你需要先拿用户名和密码(Fe)去认证服务器(CuSO4CuSO_4)去换一个 code (Cu),然后再用这个 code (Cu) 去认证服务器 (AgCl) 换一个 token (Ag)

last.png

二维码扫码登录

关键步骤

13.png

  1. PC 请求二维码
  2. 服务返回 code id
  3. PC 通过 code id 展示二维码
  4. PC 轮询二维码状态
  5. 手机扫描二维码,获得 code id
  6. 发送 token 和 code id 到服务
  7. 手机端确认登录
  8. PC 轮询发现二维码状态是已登录,同时得到 PC 端的 token。
  9. PC 端获得 token 可使用服务

由于扫码过程中使用的是 http 协议,因此 pc 在了解服务端存储的二维码状态时只能用轮询的方式(注意和 web socket)的区别。

参考资料

【1】wikipedia en.wikipedia.org/wiki/Single…

【2】华为云 www.huaweicloud.com/articles/11…

【3】简书 www.jianshu.com/p/75edcc05a…

【4】 阮一峰 www.ruanyifeng.com/blog/2014/0…

【5】 oauth.com www.oauth.com/oauth2-serv…

【6】github.com/Ethan199412…