扫码登录接入

扫码登录允许已登录的 VanCone App 用户通过扫描二维码帮助网页完成登录,无需在网页上输入账号密码。本文档描述扫码登录的完整接口契约;常规登录、Token 等其余接口见「公开接口」

扫码登录涉及两侧调用方:

  • Web 端(登录页):创建会话、展示二维码、轮询状态;
  • 扫码设备端(VanCone App):解析二维码、上报扫码、确认登录。

会话状态保存在服务端(Redis),有效期 120 秒

总体流程

Web 浏览器                        Passport Service                扫码设备(App)
    │  创建扫码会话                     │                              │
    │─────────────────────────────────>│ 生成一次性 authCode           │
    │<─── authCode ────────────────────│                              │
    │  渲染二维码                        │                              │
    │  查询状态(每 2s 轮询)             │       上报已扫码 ─────────────│
    │─────────────────────────────────>│<─────────────────────────────│
    │<─── {status: scanned} ───────────│        确认登录 ──────────────│
    │                                 │<─────────────────────────────│
    │  查询状态                         │ 确认态原子消费,签发 Token      │
    │─────────────────────────────────>│ + 下发 Cookie                 │
    │<─── {status: confirmed, token} ──│                              │
    │  登录完成,跳转回来源页面           │                              │

二维码内容约定

二维码内容为自定义协议串:

vancone://login-by-qrcode?auth-code={authCode}

扫码设备解析出 authCode 后,调用下方「上报已扫码」与「确认登录」接口。

接口明细

所有请求与响应均为 JSON,统一前缀 /api/passport/service/v1,响应遵循 Passport 标准结构 {code, message, data}(见「公开接口」的响应格式说明)。

1. 创建扫码会话(Web 调用,免 Token)

POST /api/passport/service/v1/login/qrcode

响应

{
  "code": 0,
  "message": "success",
  "data": {
    "authCode": "8fJ3kQ2p...32位URL安全随机串",
    "expiredSeconds": 120
  }
}
字段说明
authCode一次性会话码,由密码学安全随机数生成(32 字符 URL 安全串)。持有它即可完成登录,不要泄露
expiredSeconds会话有效期(秒),过期后需重新创建

2. 查询扫码状态(Web 调用,免 Token)

GET /api/passport/service/v1/login/qrcode/{authCode}

Web 端以此轮询,建议间隔 2 秒。status 取值:

status说明
pending已创建,等待扫码
scanned扫码设备已上报扫码,等待用户在手机上确认
confirmed确认完成。本响应同时下发 passport_token / passport_username Cookiedata 中附带 tokenusername;且会话被本次轮询原子消费,后续再查询一律返回 expired,Token 不可通过重复轮询二次获取
expired不存在或已过期
{
  "code": 0,
  "message": "success",
  "data": {
    "status": "confirmed",
    "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...",
    "username": "admin"
  }
}

3. 上报已扫码(扫码设备调用,需要 Token)

POST /api/passport/service/v1/login/qrcode/{authCode}/scan

认证方式与其他接口相同(passport-token 请求头或 passport_token Cookie)。幂等:重复上报返回成功。

4. 确认登录(扫码设备调用,需要 Token)

POST /api/passport/service/v1/login/qrcode/{authCode}/confirm

认证方式同上。幂等:重复确认返回成功(直到会话被 Web 端消费)。允许从 pending 直接确认——设备可将「扫码」与「确认」合并为一步。确认成功后,Web 端的下一次轮询即拿到 confirmed 与 Token。

错误返回

场景HTTP 状态码codemessage
会话不存在或已过期(scan / confirm)500-1qrcode login session not found or expired
会话状态非法流转(如确认已被消费的会话)500-1invalid qrcode login session state
scan / confirm 未携带有效 Token40111002Not authorized
创建会话服务端异常(如 Redis 不可用)500-1具体错误描述

查询状态接口不返回错误码:会话过期体现在 status: expired 中,HTTP 状态码仍为 200。

安全要点

  1. authCode 一次性有效:确认后被 Web 端轮询取走即从服务端删除,防重放
  2. scan / confirm 必须携带扫码设备自身的有效登录态,未登录设备无法确认
  3. 会话有效期仅 120 秒,过期必须重新创建,避免长期挂起的待确认会话
  4. 登录成功会写入登录历史,loginMethodQR_CODE(见「公开接口」的登录历史一节)

接入清单

Web 端(登录页):

  1. 调用「创建扫码会话」,将 authCode 按约定格式渲染为二维码
  2. 每 2 秒调用「查询扫码状态」,展示 pending / scanned / expired
  3. 轮询到 confirmed 即登录完成:服务端已在该响应中下发 Cookie
  4. 会话过期后重新执行第 1 步

扫码设备端(App):

  1. 扫码解析出 authCode
  2. 调用「上报已扫码」(需要设备自身的有效 Token)
  3. 用户确认后调用「确认登录」完成登录