扫码登录全流程原理解析
场景题: “我们在 PC 网页上登录微信、或者淘宝时,经常会看到一个二维码。你用已登录的手机 App 扫一下,PC 网页就神奇地自动登录进去了。 你能从前端、后端、App 端三方的交互视角,把整个过程的底层原理详细描述一遍吗?”
核心机制全景俯瞰
扫码登录的核心逻辑,其实就是完成一次设备间的 Token(身份)转移。 PC 端由于没有账号密码,它通过请求一个印在二维码上的“凭据暗号(Token A)”。手机 端通过扫码捕获了这个暗号,然后告诉后端:“嘿,扫描这个暗号的人是我(Token B),你放 PC 端进去吧。”
请求交互流水线分解
我们仔细分为 4 个主要阶段进行拆解:
阶段一:PC 端准备二维码与轮询机制
- PC 浏览器打开登录页,向服务端发送请求:
GET /api/qrcode/generate。 - 后端生成一个全局唯一的
qrCodeId(或者叫 UUID),并将其与状态(例如:status: WAIT_SCAN)存入 Redis 缓存,同时赋予它极短的过期时间(如 3 分钟)。 - 后端把这个
qrCodeId返回给 PC 浏览器。 - PC 浏览器拿到 ID 后,利用二维码库(如
qrcode.js)把它包装成一张二维码图形渲染展示。 - PC 进入轮询待命中:PC 端启动一个定时器,每隔哪怕 2 秒钟就去问一次后端服务:
GET /api/qrcode/check?id={qrCodeId},等待后端传来变化的消息。
阶段二:手机 App 扫码并“相认”
- 用户掏出处于已登录状态的手机 App 扫描屏幕,App 解析出了二维码背后的暗号即那个独一无二的
qrCodeId。 - 手机 App 立即向后端发送一个请求:
POST /api/qrcode/scanned(携带自身的登录态 Token 以及qrCodeId)。 - 后端接收到后,将 Redis 里这个
qrCodeId的状态更改为status: SCANNED,代表“已被某位大侠识别”。 - (在此刻,PC 端的轮询接口拿到了状态
SCANNED,页面迅速响应出"扫码成功,请在手机上确认"的 UI 过渡画面并展示被模糊的用户头像)。
阶段三:手机端确认授权
- 手持 App 弹出了授权界面,用户点击了“允许登录 PC 端”。
- App 发送决定性的 HTTP 请求:
POST /api/qrcode/confirm(同样携带自身 Token 及qrCodeId)。 - 后端接收后,终于将手机侧提供的这个用户的主体身份数据(User ID)等信息,正式和这个
qrCodeId绑定在一起,并将 Redis 状态标记为status: CONFIRMED,同时立刻在那头为 PC 端生成好专属的 PC 版 JWT Token。
阶段四:PC 获取果实,正式登录
- PC 端那孜孜不倦 2 秒一次的轮询重头戏来了。它再次发去问号寻找
status。 - 后端告知:“天王盖地虎已被确认,状态为
CONFIRMED!同时随信附上属于你的Access-Token!” - 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,前端需立刻挂起原二维码,浮上一层“二维码已过期,点击重置”的蒙层。阻止无效轮询请求继续攻击后端。用户点击后重复【阶段一】即可。

