news 2026/5/14 18:21:37

手机扫码登录详细设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手机扫码登录详细设计

手机扫码登录(Web/PC 扫码)详细设计

目标:用户在Web/PC 端看到二维码,用手机 App扫码确认后,Web/PC 端自动登录。
关键词:一次性二维码、短时会话、状态机、WebSocket/轮询、JWT/Session、风控与安全。


1. 场景与需求

1.1 核心场景

  1. Web/PC 打开登录页 → 展示二维码
  2. 手机 App 扫码 → 告知“是否在某某设备登录?”
  3. 用户在手机确认/取消 → Web/PC 实时得到结果并完成登录

1.2 业务需求

  • 低延迟:扫码后 1s 内让 Web/PC 感知状态变化(理想)
  • 高可用:登录链路要抗抖动(网络波动、页面刷新、重复扫码)
  • 安全:防伪造二维码、防重放、防钓鱼、防越权
  • 可观测:全链路埋点、日志、指标、告警
  • 可扩展:支持多端(H5/PC/小程序)、支持二次确认、支持风控

1.3 非功能指标建议

  • 二维码有效期:60–120s
  • 单二维码最多允许:N 次状态查询(防刷,如 60 次/分钟)
  • 扫码确认超时:60s
  • 登录态:
    • Web 端:HttpOnly Cookie Session 或 JWT Cookie(同站策略)
    • App 端:已有登录态(AccessToken + RefreshToken)

2. 总体架构

2.1 角色

  • Web/PC:展示二维码、监听状态变化、拿到登录态
  • App:扫码、拉取二维码信息、展示确认页、提交确认/取消
  • Auth 服务:生成二维码、维护状态机、签发 Web 登录态
  • Redis:保存二维码会话(短期)、状态、一次性票据
  • 消息通道:WebSocket(优先)或长轮询/短轮询(兜底)
  • 风控/安全:设备指纹、IP 风险、地理位置异常、黑名单等(可选)

2.2 数据与通道选择

  • 状态存储:Redis(TTL 强制过期)
  • 状态通知
    • 首选:WebSocket(服务端推送)
    • 兜底:长轮询(30s)或短轮询(1–2s)
  • Web 登录态颁发
    • 方案 A(推荐):一次性 ticket 交换 cookie/session
    • 方案 B:扫码确认后直接写入 Web session(需要能定位到 Web 连接)

3. 核心状态机设计

3.1 状态定义

  • DISPLAYED:二维码已生成(Web 已拿到并展示)
  • SCANNED:手机已扫码(已识别二维码)
  • CONFIRMED:用户在手机确认
  • CANCELLED:用户在手机取消
  • EXPIRED:二维码过期
  • CONSUMED:Web 已完成登录(票据已使用)

3.2 状态转换(严格)

DISPLAYED -> SCANNED -> CONFIRMED -> CONSUMED DISPLAYED -> SCANNED -> CANCELLED DISPLAYED -> EXPIRED SCANNED -> EXPIRED CONFIRMED -> EXPIRED (若 Web 长时间不换票据,ticket 可单独更短 TTL)

3.3 幂等与并发

  • 扫码可能重复:SCANNED状态写入应幂等(SETNX 或 Lua)
  • 确认可能重复提交:确认接口应幂等(状态已 CONFIRMED 则返回成功)
  • Web 页面刷新:同一个qrId允许重新订阅状态(WebSocket 重新连/轮询继续)

4. 二维码内容设计(非常关键)

4.1 二维码里放什么?

不要直接放 userId / token。
只放一个随机、不可预测的会话标识:

  • qrId:128-bit 随机数(Base64URL / Hex)
  • 可选:sig:服务端签名(防伪造二维码)
  • 可选:ts:生成时间戳(辅助校验)

示例(URL Scheme):

myapp://qr-login?qrId=AbCd...&ts=173...&sig=...

或(HTTPS Deep Link / Universal Link):

https://auth.example.com/qr/scan?qrId=...&ts=...&sig=...

4.2 防伪造(建议做)

  • sig = HMAC-SHA256(secret, qrId + "." + ts)
  • 服务端校验:abs(now - ts) <= 120sHMAC一致

5. Redis Key 设计

5.1 Key 结构(示例)

  • qr:login:{qrId}→ Hash

    • status:DISPLAYED / SCANNED / CONFIRMED / CANCELLED
    • createdAt
    • expireAt
    • webClientId(可选:WebSocket 连接标识)
    • deviceHint(可选:扫码设备信息,用于 Web 展示提示)
    • confirmedUserId(CONFIRMED 后写入)
    • ticket(CONFIRMED 后写入一次性票据)
  • TTL:120s(二维码本体)

  • qr:ticket:{ticket}→ String(userId 或会话信息)

    • TTL:30s(短!一次性!)

5.2 原子更新建议

用 Lua 做状态推进,确保:

  • 不允许从 CANCELLED 再 CONFIRMED
  • 不允许过期后再 CONFIRMED
  • CONFIRMED 只生成一次 ticket

6. 交互流程

6.1 Web/PC 端流程

  1. GET /api/qr-login/init→ 返回qrId、二维码图片/URL、过期时间
  2. Web 建立订阅:
    • WebSocket:ws://.../ws/qr-login?qrId=...
    • 或轮询:GET /api/qr-login/poll?qrId=...
  3. 收到状态:
    • SCANNED:UI 提示“已扫码,请在手机确认”
    • CONFIRMED:拿到ticket,调用POST /api/qr-login/exchange换取登录态
    • CANCELLED/EXPIRED:提示并刷新二维码

6.2 App 端流程

  1. 扫码解析qrId/ts/sig
  2. 调用POST /api/qr-login/scan(App 已登录,带 App Token)
  3. 服务端返回 Web 端信息(设备、地点、浏览器)用于确认页展示
  4. 用户点击确认:
    • POST /api/qr-login/confirm
  5. 或取消:
    • POST /api/qr-login/cancel

7. API 设计(REST 示例)

7.1 生成二维码

GET/api/qr-login/init

响应:

{"qrId":"AbCdEf...","qrUrl":"myapp://qr-login?qrId=...&ts=...&sig=...","expireInSeconds":120}

7.2 Web 轮询状态(兜底)

GET/api/qr-login/poll?qrId=...&sinceVersion=...

响应:

{"status":"SCANNED","deviceHint":"iPhone 15 · 上海","ticket":null,"expireInSeconds":80}

7.3 App 扫码上报

POST/api/qr-login/scan

{"qrId":"...","ts":1730000000,"sig":"..."}

返回(给 App 确认页展示):

{"status":"SCANNED","webInfo":{"ipCity":"New York","browser":"Chrome","os":"Windows","time":"2026-01-31T12:00:00Z"}}

7.4 App 确认登录

POST/api/qr-login/confirm

{"qrId":"..."}

7.5 App 取消

POST/api/qr-login/cancel

{"qrId":"..."}

7.6 Web 换票据拿登录态

POST/api/qr-login/exchange

{"qrId":"...","ticket":"TICKET_..."}

响应:Set-Cookie(Session/JWT Cookie) +{ "ok": true }


8. WebSocket 推送设计(推荐)

8.1 建连

GET ws://auth.example.com/ws/qr-login?qrId=...

服务端验证:

  • qrId存在且未过期
  • 绑定连接connIdqr:login:{qrId}.webClientId

8.2 推送消息

{"qrId":"...","status":"SCANNED","deviceHint":"..."}

CONFIRMED推送可带ticket(建议只带 ticket,不带 userId):

{"qrId":"...","status":"CONFIRMED","ticket":"TICKET_..."}

8.3 多实例

  • Redis Pub/Sub 或 MQ 广播状态变更
  • 各节点维护本地qrId -> wsSession映射,收到事件后推送

9. 安全设计清单

  • ticket一次性GETDEL或 Lua 原子删除
  • sig+ts防伪造二维码
  • Web 端 Cookie:HttpOnly + Secure + SameSite
  • exchange校验Origin/Referer
  • 限流:init/poll/scan/confirm 分别按 IP/userId 维度
  • App 确认页展示 Web 端信息(地点/浏览器/时间),让用户识别异常
  • 风控扩展:异地登录/代理/VPN/黑名单/二次验证

10. 可观测性

关键指标:

  • init 成功率/耗时
  • 扫码率(init→scan)
  • 确认率(scan→confirm)
  • 换票成功率(confirm→exchange)
  • 过期率、取消率

日志:

  • qrId贯穿全链路(trace tag)
  • userId 脱敏(hash),IP/UA 记录用于风控追踪

11. Java 落地要点(Spring Boot)

关键组件:

  • QrLoginService:状态机推进(Lua)
  • RedisRepository:Key/TTL 封装
  • WebSocketHandler:连接管理与推送
  • AuthTokenService:签发 Web session/JWT
  • RateLimit:限流(网关优先)

Lua(伪代码简化):

-- KEYS[1] = qr:login:{qrId}-- ARGV[1] = targetStatuslocalst=redis.call('HGET',KEYS[1],'status')ifnotstthenreturn{err="NOT_FOUND"}endifst=='CANCELLED'orst=='CONSUMED'orst=='EXPIRED'thenreturn{ok=0,status=st}end-- ...按状态推进(略)return{ok=1}

12. 必测用例清单

  • 正常:init → scan → confirm → exchange
  • cancel:scan → cancel(Web 及时感知)
  • 过期:init 后不扫码,Web 刷新二维码
  • 重复扫码/重复确认/重复 exchange(幂等 + ticket 一次性)
  • Web 刷新/断网重连(仍能继续)
  • 限流触发与恢复
  • 伪造 sig / 篡改 qrId / 过期 ts 全部失败

13. 常见坑

  • 把用户信息/Token 塞进二维码(等于送号)
  • ticket TTL 太长(被截获风险更大)
  • 只做轮询(高并发下把服务打爆)
  • 不做幂等(重复扫码/确认导致状态乱)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 14:42:40

基于轮滑网站《无与轮比》购物网 任务书

目录 轮滑网站《无与轮比》购物网任务书介绍网站定位与目标核心功能模块技术支持与运营数据与安全扩展计划 项目技术支持可定制开发之功能亮点源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作 轮滑网站《无与轮比》购物网任务书介绍 网站定…

作者头像 李华
网站建设 2026/5/10 6:35:14

导师严选!8款一键生成论文工具测评:本科生毕业论文全攻略

导师严选&#xff01;8款一键生成论文工具测评&#xff1a;本科生毕业论文全攻略 2026年学术写作工具测评&#xff1a;为何值得一看&#xff1f; 随着高校论文写作需求的不断增长&#xff0c;越来越多的本科生开始寻求高效、专业的论文辅助工具。然而&#xff0c;市面上的AI论文…

作者头像 李华
网站建设 2026/5/14 15:13:24

ArcGIS Python零基础脚本开发教程---10.5 列出数据函数

掌握9大List函数,让数据遍历与管理变得简单高效 📊 List函数全家福概览 函数名 功能描述 常用场景 ListDatasets 列出工作空间中的数据集 管理要素数据集 ListFeatureClasses 列出要素类 批量处理矢量数据 ListFields 列出字段信息

作者头像 李华
网站建设 2026/5/10 0:15:27

开题报告-基于云开发的跑腿代拿小程序

目录 基于云开发的跑腿代拿小程序开题报告项目背景核心功能技术方案创新点预期成果进度计划 项目技术支持可定制开发之功能亮点源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作 基于云开发的跑腿代拿小程序开题报告 项目背景 随着移动互联…

作者头像 李华
网站建设 2026/5/9 4:50:17

小白也能上手!专业领域大模型入门与实战指南

文章介绍了专业领域大模型的概念、发展时机及适合人群。专业领域大模型是基于开源基座通过行业数据微调&#xff0c;聚焦特定细分领域的模型&#xff0c;具有精准解决行业问题的优势。当前发展时机已成熟&#xff0c;表现在市场规模增长、开源基座成熟、微调工具可视化和行业痛…

作者头像 李华