2026/4/18 0:49:26
网站建设
项目流程
天津哪家网站做的好,WordPress搬家后所有页面404,ai做的网站怎么切图,哪里可以申请免费域名手机扫码登录#xff08;Web/PC 扫码#xff09;详细设计 目标#xff1a;用户在 Web/PC 端看到二维码#xff0c;用 手机 App 扫码确认后#xff0c;Web/PC 端自动登录。 关键词#xff1a;一次性二维码、短时会话、状态机、WebSocket/轮询、JWT/Session、风控与安全。 …手机扫码登录Web/PC 扫码详细设计目标用户在Web/PC 端看到二维码用手机 App扫码确认后Web/PC 端自动登录。关键词一次性二维码、短时会话、状态机、WebSocket/轮询、JWT/Session、风控与安全。1. 场景与需求1.1 核心场景Web/PC 打开登录页 → 展示二维码手机 App 扫码 → 告知“是否在某某设备登录”用户在手机确认/取消 → Web/PC 实时得到结果并完成登录1.2 业务需求低延迟扫码后 1s 内让 Web/PC 感知状态变化理想高可用登录链路要抗抖动网络波动、页面刷新、重复扫码安全防伪造二维码、防重放、防钓鱼、防越权可观测全链路埋点、日志、指标、告警可扩展支持多端H5/PC/小程序、支持二次确认、支持风控1.3 非功能指标建议二维码有效期60–120s单二维码最多允许N 次状态查询防刷如 60 次/分钟扫码确认超时60s登录态Web 端HttpOnly Cookie Session 或 JWT Cookie同站策略App 端已有登录态AccessToken RefreshToken2. 总体架构2.1 角色Web/PC展示二维码、监听状态变化、拿到登录态App扫码、拉取二维码信息、展示确认页、提交确认/取消Auth 服务生成二维码、维护状态机、签发 Web 登录态Redis保存二维码会话短期、状态、一次性票据消息通道WebSocket优先或长轮询/短轮询兜底风控/安全设备指纹、IP 风险、地理位置异常、黑名单等可选2.2 数据与通道选择状态存储RedisTTL 强制过期状态通知首选WebSocket服务端推送兜底长轮询30s或短轮询1–2sWeb 登录态颁发方案 A推荐一次性 ticket 交换 cookie/session方案 B扫码确认后直接写入 Web session需要能定位到 Web 连接3. 核心状态机设计3.1 状态定义DISPLAYED二维码已生成Web 已拿到并展示SCANNED手机已扫码已识别二维码CONFIRMED用户在手机确认CANCELLED用户在手机取消EXPIRED二维码过期CONSUMEDWeb 已完成登录票据已使用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。只放一个随机、不可预测的会话标识qrId128-bit 随机数Base64URL / Hex可选sig服务端签名防伪造二维码可选ts生成时间戳辅助校验示例URL Schememyapp://qr-login?qrIdAbCd...ts173...sig...或HTTPS Deep Link / Universal Linkhttps://auth.example.com/qr/scan?qrId...ts...sig...4.2 防伪造建议做sig HMAC-SHA256(secret, qrId . ts)服务端校验abs(now - ts) 120s且HMAC一致5. Redis Key 设计5.1 Key 结构示例qr:login:{qrId}→ HashstatusDISPLAYED / SCANNED / CONFIRMED / CANCELLEDcreatedAtexpireAtwebClientId可选WebSocket 连接标识deviceHint可选扫码设备信息用于 Web 展示提示confirmedUserIdCONFIRMED 后写入ticketCONFIRMED 后写入一次性票据TTL120s二维码本体qr:ticket:{ticket}→ String(userId 或会话信息)TTL30s短一次性5.2 原子更新建议用 Lua 做状态推进确保不允许从 CANCELLED 再 CONFIRMED不允许过期后再 CONFIRMEDCONFIRMED 只生成一次 ticket6. 交互流程6.1 Web/PC 端流程GET /api/qr-login/init→ 返回qrId、二维码图片/URL、过期时间Web 建立订阅WebSocketws://.../ws/qr-login?qrId...或轮询GET /api/qr-login/poll?qrId...收到状态SCANNEDUI 提示“已扫码请在手机确认”CONFIRMED拿到ticket调用POST /api/qr-login/exchange换取登录态CANCELLED/EXPIRED提示并刷新二维码6.2 App 端流程扫码解析qrId/ts/sig调用POST /api/qr-login/scanApp 已登录带 App Token服务端返回 Web 端信息设备、地点、浏览器用于确认页展示用户点击确认POST /api/qr-login/confirm或取消POST /api/qr-login/cancel7. 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-CookieSession/JWT Cookie { ok: true }8. WebSocket 推送设计推荐8.1 建连GET ws://auth.example.com/ws/qr-login?qrId...服务端验证qrId存在且未过期绑定连接connId到qr:login:{qrId}.webClientId8.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 原子删除sigts防伪造二维码Web 端 CookieHttpOnly Secure SameSiteexchange校验Origin/Referer限流init/poll/scan/confirm 分别按 IP/userId 维度App 确认页展示 Web 端信息地点/浏览器/时间让用户识别异常风控扩展异地登录/代理/VPN/黑名单/二次验证10. 可观测性关键指标init 成功率/耗时扫码率init→scan确认率scan→confirm换票成功率confirm→exchange过期率、取消率日志qrId贯穿全链路trace taguserId 脱敏hashIP/UA 记录用于风控追踪11. Java 落地要点Spring Boot关键组件QrLoginService状态机推进LuaRedisRepositoryKey/TTL 封装WebSocketHandler连接管理与推送AuthTokenService签发 Web session/JWTRateLimit限流网关优先Lua伪代码简化-- KEYS[1] qr:login:{qrId}-- ARGV[1] targetStatuslocalstredis.call(HGET,KEYS[1],status)ifnotstthenreturn{errNOT_FOUND}endifstCANCELLEDorstCONSUMEDorstEXPIREDthenreturn{ok0,statusst}end-- ...按状态推进略return{ok1}12. 必测用例清单正常init → scan → confirm → exchangecancelscan → cancelWeb 及时感知过期init 后不扫码Web 刷新二维码重复扫码/重复确认/重复 exchange幂等 ticket 一次性Web 刷新/断网重连仍能继续限流触发与恢复伪造 sig / 篡改 qrId / 过期 ts 全部失败13. 常见坑把用户信息/Token 塞进二维码等于送号ticket TTL 太长被截获风险更大只做轮询高并发下把服务打爆不做幂等重复扫码/确认导致状态乱