第5章用户登录服务——5.7 扫码登录

第5章用户登录服务——5.7 扫码登录
John Yaml很多互联网产品不仅提供了移动端应用,还提供了PC端应用或网页访问方式,比如爱奇艺、腾讯视频等视频类产品,以及淘宝、微信等国民级产品。这些兼顾PC端用户体验的产品一般都提供了扫码登录功能:如果用户已在移动端登录,那么在PC端可以通过在移动端应用内扫描二维码的方式完成一键登录。
手机扫码登录方式具有方便快捷、安全性高、密码管理成本低、用户体验好等优势,后面我们会讨论这个功能的技术实现。
5.7.1 二维码
二维码是一种可以存储大量信息的矩阵条形码,最早是在1994年由一家日本公司发明的。随着移动互联网的发展,二维码得到了非常广泛的发展和应用。
二维码采用特殊的编码方式将数字信息编码成黑白相间的矩阵图案,且编码方式多种多样,例如QR码、Data Matrix码等。使用扫描仪设备或相机对二维码进行扫描,可以将二维码解码转换回数字信号。二维码种类繁多,这里我们仅需要知道一段数据可以被编码生成二维码图片,使用手机扫描二维码图片可以将其解码回原始数据即可。
5.7.2 扫码登录的场景介绍
假设小A是Friendy产品用户,并且他已经在自己的手机上登录了Friendy客户端。有一天小A访问网页版Friendy,为了操作方便,他在网页登录环节选择扫码登录,步骤如下。
- 小A在网页端点击“扫码登录”。
- 网页端展示了一个二维码,并提示小A “请打开手机Friendy客户端扫一扫登录”。
- 小A打开手机,使用Friendy客户端的“扫一扫”功能扫描二维码。
- 扫码完成,Friendy客户端自动跳转到登录确认页面,询问小A是否确认登录。
- 小A点击“确认”按钮登录。
- 网页显示登录成功,小A在网页端登录了与客户端相同的账号。
相信大家都很熟悉上述步骤,因为微信、淘宝等应用的扫码登录均采用类似的操作流程。接下来通过分析每一步后发生了什么事情来介绍扫码登录的技术实现。
5.7.3 扫码登录的技术实现
小A在网页端点击“扫码登录”,网页端会展示一个二维码,这个二维码编码的原始数据是一条跳转指令和一个UUID。
- 跳转指令:用于告知客户端,请跳转到登录确认页面。
- UUID:用于全局唯一标识这次扫码登录请求,也可以将其理解为二维码的唯一ID。
所以,小A点击“扫码登录”,网页端会先从服务端获取二维码原始数据;服务端收到扫码登录请求后生成新的UUID,并记录此UUID状态为未扫码,然后将与客户端约定的跳转指令和UUID响应给网页端,作为二维码原始数据;网页端收到数据,编码生成二维码图片并展示在页面上。
小A使用已登录的手机客户端扫描二维码,将二维码解码得到跳转指令和UUID,于是客户端跳转到登录确认页面,等待小A点击“确认”按钮后携带UUID向服务端发起确认登录请求。由于手机客户端是已登录状态,所以服务端可以从确认登录请求中识别用户ID,然后记录UUID已被此用户ID成功扫描。至此,手机客户端的工作就完成了。
接下来,网页端需要知晓登录是否成功。因为网页端无法感知到用户什么时候扫码,所以网页端在二维码图片展示出来后会周期性向服务端轮询:此UUID的二维码是否已被扫描、被谁扫描。服务端查询到UUID的二维码被小A扫描了,于是生成与登录态相关的SessionlD或新令牌下发给网页端。小A在网页端的后续任何请求都会携带登录态信息,且请求被识别出的用户ID与客户端的完全一致,网页端登录正式完成。
可以看到,实现扫码登录的技术关键是登录态,只有已在手机客户端登录的用户扫码登录网页版,服务端才可以构建二维码与用户的关联关系。服务端可以使用Redis存储一个二维码是否被扫描的信息:设置Key为UUID,如果二维码被某个用户扫描了,则设置 Value为用户ID;如果未被扫描,则设置Value为0。此外,一般需要为二维码设置有效期。如果在指定的时间内(如1min)没有完成扫码,则二维码应该失效。所以,也需要为Key设置一个过期时间。
扫码登录的技术实现流程如下所述,如图5-10所示。
- 用户在网页端发起扫码登录请求。
- 网页端向用户登录服务请求生成二维码原始数据。
- 用户登录服务生成UUID,并以其为Key、以0为Value写入Redis。
- 用户登录服务将跳转指令和UUID组装为
redirect_login_confirm:UUID
,作为原始数据下发到网页端。 - 网页端将原始数据编码生成二维码图片并展示。
- 网页端开启本地后台线程向用户登录服务轮询UUID对应二维码的扫码状态。
- 用户打开已登录的手机客户端扫描二维码,解析得到UUID并跳转到确认登录页面。
- 用户点击“确认”按钮登录,手机客户端携带UUID请求用户登录服务。
- 用户登录服务从Redis中查询UUID是否存在。如果存在,则根据手机客户端请求中的长短令牌获取用户ID,将UUID在Redis中的Value设置为用户ID;否则,说明扫码超时。
- 网页端后台线程轮询时,用户登录服发现Redis中UUID的Value是一个用户ID,说明此二维码已被该用户扫码确认。
- 用户登录服务根据用户ID生成Session数据、长短令牌,然后响应给网页端,下发登录态信息。
- 用户在网页端的所有请求均携带长短令牌,表示用户已成功登录,可正常访问网站。
总结
扫码登录的技术实现流程?
- 用户在网页端发起扫码登录请求。
- 网页端向用户登录服务请求生成二维码原始数据。
- 用户登录服务生成UUID,并以其为Key、以0为Value写入Redis。
- 用户登录服务将跳转指令和UUID组装为
redirect_login_confirm:UUID
,作为原始数据下发到网页端。 - 网页端将原始数据编码生成二维码图片并展示。
- 网页端开启本地后台线程向用户登录服务轮询UUID对应二维码的扫码状态。
- 用户打开已登录的手机客户端扫描二维码,解析得到UUID并跳转到确认登录页面。
- 用户点击“确认”按钮登录,手机客户端携带UUID请求用户登录服务。
- 用户登录服务从Redis中查询UUID是否存在。如果存在,则根据手机客户端请求中的长短令牌获取用户ID,将UUID在Redis中的Value设置为用户ID;否则,说明扫码超时。
- 网页端后台线程轮询时,用户登录服发现Redis中UUID的Value是一个用户ID,说明此二维码已被该用户扫码确认。
- 用户登录服务根据用户ID生成Session数据、长短令牌,然后响应给网页端,下发登录态信息。
- 用户在网页端的所有请求均携带长短令牌,表示用户已成功登录,可正常访问网站。
本章小结
用户注册与登录是几乎所有互联网应用的最基础也是最重要的功能。本章介绍了多种常见的登录方式,包括账号密码登录、手机号登录和邮箱登录、手机号一键登录以及第三方登录。
- 账号密码登录:这是最常规的登录方式,用户体验一般。实现此登录方式的重点是保障用户的账号密码不被泄露,包括使用非对称加密算法加密账号密码明文,使用HTTPS加密通信链路,以及使用单向加密算法存储密码。
- 手机号登录和邮箱登录:手机号和邮箱有易于验证使用者身份的优势,所以此登录方式需要下发动态验证码,以及存储用户授权记录。
- 手机号一键登录:这是最近几年非常流行的、真正意义上的一键登录方式。此登录方式抛弃了收发短信验证码的步骤,而是依赖移动运营商开放的能力,自动获取用户当前移动设备的手机号掩码来验证用户。
- 第三方登录:借助各大拥有海量用户的第三方平台,实现第三方用户到乙方应用的转化。乙方应用客户端、第三方应用客户端、乙方应用服务端、第三方应用服务端四者遵循OAuth 2标准实现第三方登录,依次获取授权码、访问令牌、用户信息。第三方平台使用openlD作为用户唯一标识,我们需要记录openlD与乙方应用的用户ID的关联关系。
无论用户以何种方式登录,最后一步服务端都要告知客户端接下来的请求携带用户登录态信息。这样一来,对于用户登录后发出的请求,服务端能够做到准确识别请求的发起者,以及用户是否已登录。关于请求如何携带用户登录态信息,本章介绍了3种解决方案。
- Session方案:服务端需要为每个用户、每个登录设备在登录后创建Session代表此次登录会话,并在Redis中进行管理;用户请求在Cookie中携带对应的SessionlD,服务端根据SessionlD从Redis中查询Session即可识别登录态。此方案的优点是服务端易于管理用户登录行为,而缺点是存储资源占用和请求量都极大,可能会为用户请求带来额外的延时和可用性下降的问题。
- 令牌方案:纯计算型登录态方案,用户登录后,服务端将包含用户ID、设备ID等的主要信息编码到一个令牌中并使用专用规则加密令牌。请求会在http请求头中携带令牌,如果这个令牌可以被服务端有效地解密和解析,则认为是合法用户登录。此方案的优点是不依赖任何存储系统,登录态识别的性能极高,而缺点是服务端无法管理用户登录行为,难以统计登录数据。
- 长短令牌方案:此方案结合了Session方案与令牌方案的优点,其中长令牌用于Session方案,短令牌用于令牌方案。短令牌相当于长令牌的缓存,服务端先解析短令牌,除非在短令牌的有效期内就完成了登录态识别,否则会使用长令牌查询Session。短令牌的有效期设置是一种权衡:有效期越长,越能发挥令牌方案的优势,但同时放大了Session方案的缺点;有效期越短,Session的压力越大,但是踢用户下线、统计在线人数的实效性高。