作者:李嘉豪 lijiahao043@ke.com
这篇文章的主题是互联网公司和登录相关的那些技术栈,分为 3 个部分。单点登录,Oauth2.0 和 扫码登录。虽然不能涵盖所有的登录体系,但是掌握了这三种登录技术,理解其他和登录有关的技术体系,对你而言绝非难事。
单点登录
单点登录的意义
互联网公司也是近几年才有的概念,十几年前,一个公司,一台服务器,一个域名是常有的事。但现在,一个公司有多个部门,多个业务线,每一个部门都有独立的服务,每一套服务对应一个域名。对于公司而言,每一个部门不想花时间单独搞一套登陆系统;对于个人而言,我登录了你司的 a 服务,我不想再在使用 b 服务的时候,再登陆一次。 于是,单点登录应运而生。
如何设计单点登录
假如公司让你设计一套登录系统,下面这套设计方案只会让用户抓狂。
所以,下面的情形中,换做你来登录设计,你如何设计呢?‘
单点登录的两大方式
基于 cookie 共享的单点登录系统
- 访问 a.ke.com,检查到没有登录态(token)
- my-login.ke.com?redirectUrl=a.ke.com
- 登陆成功后,二级域名也就是,ke.com 域下注入 token
- b.ke.com 如果再登陆,发现有 token,发送异步请求验证 token,有效,返回 html 字符串,也就是 b.ke.com 的主页面。
但是,这种单点登录方式有什么问题?
随着企业规模的扩大,业务的拓张,二级域名有可能并不相同,此时再用基于 cookie 共享的单点登录会无效。
**把 token 拼到重定向 url 上的方案
- 登录 a.ke.com,发现没有登录态(token)
- my-login.ke.com?redirectUrl=a.ke.com
- my-login.ke.com 域下注入 token
- a.ke.com?token=xxx
- a.ke.com 域下注入 token
- b.lianjia.com
- my-login.ke.com 下已有 token
- b.lianjia.com?token=xxx
- b.lianjia.com 下注入 token
单点登录 demo
为了方便读者深刻地体会单点登录原理,作者提供了一个单点登录的小 demo,个人非常建议读者把这个 demo git clone 下来跑一跑,这比只看文章形成的理解要深刻的多。
demo 技术栈
- 原生 nodejs
- post 的参数
- set-cookie domain
- form type=’hidden’
- ejs 模板引擎
- ssr 服务端渲染 我稍微展开一下 demo 里面比较值得说的几个点。post 请求获取参数的过程并非一次性获得的,而是需要多次获得参数 chunk,并把它们合并起来,这是因为服务器端不知道请求参数的多少( post 参数不像 get 参数那样有上限,参数量有可能非常大);另外一点是 set-cookie 的 domain 的字段,这个字段告诉了浏览器,服务端想注入的 cookie 只在哪个域名下是有效果的。另外一个知识点是 type='hidden' 这个属性的含义,这种方式可以以一种对用户透明的方式把相关参数传给服务端。
这个小 demo 也用到了服务端渲染的相关知识。这里简单介绍一下客户端渲染和服务端渲染的区别,客户端渲染指的是第一次从服务端拿 html,html 里面是没有数据的,当 js 加载以后,js 里会发异步请求获得数据,再更新 html。服务端渲染指的是服务器会直接返回具有数据的 html。
链接
OAuth 2.0 原理
OAuth 2.0 的意义
先给大家展示两个典型用到了 OAuth 2.0 的场景:
请大家带入想一想下面这个情形:
我是一个小公司叫 B+,我要用贝壳的房源信息,在这个基础上对数据进行一定的分析和加工,那么我需要用户登录贝壳,调用贝壳一些开放 api 以获取用户的数据,但是用户一定不希望我直接获得他在贝壳上面的用户名和密码。
这个时候我们就需要使用 Oauth。
第一方,第二方和第三方之争
首先问大家两个问题。
在 B+ 的那个例子里面,请问谁是第三方?
在豆瓣的那个例子里面,请问谁是第三方?
其实网上并没有一个官方的说法能把第一方,第二方和第三方讲的很清楚。一般而言,第三方指的是用别人数据的那个应用。所以,如果我们用 B+ 登录贝壳获取贝壳的数据时,第三方指的是 B+。而在豆瓣微信登录的那个例子里,豆瓣需要登录微信获取用户信息,按照上面的定义,似乎豆瓣才是第三方吧,但对于豆瓣而言,你可以说用微信登录是第三方登录。所以大家这块不要混淆,在 oauth 标准里谁是第三方,和用第三方登录是两个概念。
OAuth 2.0 的原理
回到我们第一个例子,大家想一想能否这样设计,假如你是贝壳负责第三方登录这块的人,你让 B+ 的开发者在自己的登录页面上直接输入用户名和密码,B+ 的服务直接把用户名和密码传过来以作为用户凭证获取贝壳的数据?
答案一定是否定的,因为对于客户而言,他的贝壳用户名和密码等于直接给了 B+,假如 B+ 把贝壳的用户名和密码记录了下来,那么用户信息很容易被泄露甚至交易。
所以说,我们需要一种手段,这种手段既可以让第一方有获取第三方数据的凭证,同时又不直接获取用户的用户名和密码。这种手段就是 OAuth2.0
简易版 OAuth 2.0
- 用户访问 www.b-plus.com,点击登录贝壳
- login.beike.com?redirectUrl=www.b-plus.com
- www.b-plus.com?token=xxx
至此,用户在想获取微信数据的时候,就不需要再登录了,同时,也不需要用户名和密码。但是,由于 token 是放在 url 上的,它并不安全,假如在传输过程中有人把这个 token 截获到,它依然可以用它获取贝壳的用户信息。
oauth 2.0 授权码模式
- 用户访问 www.b-plus.com
- login.beike.com?redirectUrl=www.b-plus.com
- www.b-plus.com?code=xxx
- 服务获得 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)去认证服务器()去换一个 code (Cu),然后再用这个 code (Cu) 去认证服务器 (AgCl) 换一个 token (Ag)
二维码扫码登录
关键步骤
- PC 请求二维码
- 服务返回 code id
- PC 通过 code id 展示二维码
- PC 轮询二维码状态
- 手机扫描二维码,获得 code id
- 发送 token 和 code id 到服务
- 手机端确认登录
- PC 轮询发现二维码状态是已登录,同时得到 PC 端的 token。
- 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…