扫码登录全流程原理解析

场景题: “我们在 PC 网页上登录微信、或者淘宝时,经常会看到一个二维码。你用已登录的手机 App 扫一下,PC 网页就神奇地自动登录进去了。 你能从前端、后端、App 端三方的交互视角,把整个过程的底层原理详细描述一遍吗?”

核心机制全景俯瞰

扫码登录的核心逻辑,其实就是完成一次设备间的 Token(身份)转移。 PC 端由于没有账号密码,它通过请求一个印在二维码上的“凭据暗号(Token A)”。手机 端通过扫码捕获了这个暗号,然后告诉后端:“嘿,扫描这个暗号的人是我(Token B),你放 PC 端进去吧。”

请求交互流水线分解

我们仔细分为 4 个主要阶段进行拆解:

阶段一:PC 端准备二维码与轮询机制

  1. PC 浏览器打开登录页,向服务端发送请求:GET /api/qrcode/generate
  2. 后端生成一个全局唯一的 qrCodeId(或者叫 UUID),并将其与状态(例如:status: WAIT_SCAN)存入 Redis 缓存,同时赋予它极短的过期时间(如 3 分钟)。
  3. 后端把这个 qrCodeId 返回给 PC 浏览器。
  4. PC 浏览器拿到 ID 后,利用二维码库(如 qrcode.js)把它包装成一张二维码图形渲染展示。
  5. PC 进入轮询待命中:PC 端启动一个定时器,每隔哪怕 2 秒钟就去问一次后端服务:GET /api/qrcode/check?id={qrCodeId},等待后端传来变化的消息。

阶段二:手机 App 扫码并“相认”

  1. 用户掏出处于已登录状态的手机 App 扫描屏幕,App 解析出了二维码背后的暗号即那个独一无二的 qrCodeId
  2. 手机 App 立即向后端发送一个请求:POST /api/qrcode/scanned(携带自身的登录态 Token 以及 qrCodeId)。
  3. 后端接收到后,将 Redis 里这个 qrCodeId 的状态更改为 status: SCANNED,代表“已被某位大侠识别”。
  4. (在此刻,PC 端的轮询接口拿到了状态 SCANNED,页面迅速响应出**"扫码成功,请在手机上确认"**的 UI 过渡画面并展示被模糊的用户头像)。

阶段三:手机端确认授权

  1. 手持 App 弹出了授权界面,用户点击了“允许登录 PC 端”。
  2. App 发送决定性的 HTTP 请求:POST /api/qrcode/confirm(同样携带自身 Token 及 qrCodeId)。
  3. 后端接收后,终于将手机侧提供的这个用户的主体身份数据(User ID)等信息,正式和这个 qrCodeId 绑定在一起,并将 Redis 状态标记为 status: CONFIRMED,同时立刻在那头为 PC 端生成好专属的 PC 版 JWT Token。

阶段四:PC 获取果实,正式登录

  1. PC 端那孜孜不倦 2 秒一次的轮询重头戏来了。它再次发去问号寻找 status
  2. 后端告知:“天王盖地虎已被确认,状态为 CONFIRMED!同时随信附上属于你的 Access-Token!”
  3. PC 前端结束定时轮询,拿到 Token 存入 localStorage,立刻使用 router.push 将页面飞驰跳转向系统首页。登录大捷。

面试追问防雷指南

Q:为什么 PC 端要用轮询(Polling)去查?不能用 WebSocket 吗? A:完全可以用 WebSocket 甚至 Server-Sent Events (SSE)。事实上,如果系统的基建极为强大,使用 WebSocket 能免除轮询的海量无效 HTTP 开销,且服务端状态更新后前端能极其丝滑无延迟被驱动。 但在实际工程(比如微信老版本、京东扫码)中,轮询依旧占据极大数量。因为扫码页通常并不常驻,生命周期极短最多存在一分钟。与其为了一个扫码投入成本维护一条沉重的长连接、心跳机制还要防止断线重连,简单粗暴可依赖的“短轮询”,反而是工程 ROI(投资回报率)上极佳的选择。

Q:如果二维码过期了怎么办? A:为了安全,生成 qrCodeId 时在 Redis 一定存在过期剔除机制。若 PC 轮询时接口返回 status: EXPIRED,前端需立刻挂起原二维码,浮上一层“二维码已过期,点击重置”的蒙层。阻止无效轮询请求继续攻击后端。用户点击后重复【阶段一】即可。