spec.md 7.7 KB

017 - Apple / Google / LINE 三方登录

背景

C 端 app 现仅支持「手机号 + 短信验证码」登录(/infouser/user/lodeing,登录即注册)。本特性新增 Apple / Google / LINE 三方登录,降低台湾市场获客与登录摩擦。鉴权沿用现有自写 JwtUtil(HS256 JWT + Redis 会话),不引入新鉴权体系。

锁定的关键决策(业务确认)

  1. 手机号始终是主键:三方账号只是绑在「某个手机号账号」上的快捷入口,不在 InfoUser 上落三方 ID(独立表 info_user_oauth 记录绑定关系)。
  2. 首次使用任一三方登录强制手机验证:拿到手机号后查 info_user——已注册则关联到该老账号(写一条 oauth 绑定),未注册则新建账号后再绑定。不以邮箱做关联
  3. 不使用 Apple 邮箱信息:Apple 只取 identityToken 的 sub(稳定用户ID),忽略 email。
  4. 记录登录渠道 loginType:因一个用户可绑多家三方,loginType 不落用户表,而写入本次会话的 JWT claimprovider)。

User Story

US1 - 三方登录入口 (P0)

客户在登录页选 Apple/Google/LINE,客户端拿到 provider 凭证后调后端校验。

US2 - 首次登录手机验证 + 绑定 (P0)

首次用某三方账号登录时,强制输手机号 + 短信验证码:手机号已注册→关联该账号;未注册→新建账号;随后建立 oauth 绑定。

US3 - 已绑定快捷登录 (P0)

已绑过该三方的账号再次登录,校验凭证通过即直接签发 token,免手机验证。

Functional Requirements

  • FR-001: 提供 POST /infouser/user/oauthLogin {provider, credential, ...},后端校验 provider 凭证换取稳定 providerUid。用户 provider 为 applegoogleline(旧版)、line_user;骑手为 apple_ridergoogle_riderline_rider;商家为 apple_merchantgoogle_merchantline_merchant
  • FR-002: 凭证校验三选一:Apple=验 ES256 identityToken 取 sub;Google=tokeninfo HTTP 验真取 sub 并校 audience;LINE=前端传授权 code,后端用 code+clientSecret+clientId 向 oauth2/v2.1/token 换 access_token,再调 v2/profile 取 userId(Authorization Code 流程,不直接收前端 accessToken)。
  • FR-003: 按 (provider, providerUid) 查 info_user_oauth:命中→校验用户 status/del_flag 正常后直接签发 token(claim provider)返回;未命中→缓存 {provider,providerUid} 到 Redis(短TTL),返回 needPhone + tempKey。
  • FR-004: 提供 POST /infouser/user/oauthBindPhone {tempKey, phone, code, ...}:取回缓存的 providerUid + 验短信码(复用 lodeing 逻辑,含万能码 8888)→ getuser(phone):已注册→关联;未注册→createUser 新建;随后 insert info_user_oauth(user_id, provider, provider_uid)
  • FR-005: 新建用户昵称统一用手机号(与现有 createUser 一致),avatar 留空,不用 provider 的昵称/头像。
  • FR-006: token claim 增加 provider 字段(apple/google/line_user/line_rider/line_merchant;手机号登录为 phone),供登录渠道统计或「未绑手机限制」类约束使用。
  • FR-007: 登录端点 @Anonymous 放行;受保护接口继续走 @Auth,零额外接入。
  • FR-008: 凭证校验失败 / tempKey 过期 / 短信码错误 → 明确错误提示,不签发 token、不建账号。
  • FR-009(2026-08-05 增量,2026-09-04 扩展): LINE「唤起 LINE App / 系统浏览器」流程下前端拿不到 code,使用服务端回调 GET /auth/line/callback@Anonymous,LineCallbackController):接收 provider 与 LINE 重定向的 code → 复用 verify(provider, code) 换 token 取 userId → 已绑定签 token / 未绑定生成 tempKey → 302 跳回 provider 对应 App scheme(?token= / ?needPhone=1&tempKey= / ?error=,未绑定时 App 再调 /infouser/user/oauthBindPhone)。原 /oauthLogin 保留,覆盖前端自取 code 场景(H5/webview/SDK)。
  • FR-010(2026-09-04 增量): LINE 登录按客户端区分 line_userline_riderline_merchant。三个客户端继续自行构造 LINE 授权地址,共用 GET /auth/line/callback,通过回调 URL 的 provider 查询参数选择对应 Channel 配置;provider 只能取上述三个白名单值。
  • FR-011: 三个 LINE Channel 使用各自的 Channel ID、Channel Secret、redirect URI 和 App 回跳地址。换取 access token 时提交的 redirect URI MUST 与发起授权时完全一致,包括 provider 查询参数。
  • FR-012: line_user 沿用普通用户首次登录的手机号关联/新建逻辑;line_rider 只允许绑定已有且有效的 userType=2 账号;line_merchant 只允许绑定已有且有效的 userType=1/3/4/5 账号,不自动创建骑手或商家。
  • FR-013: 普通用户手机号继续使用 info_user.phone;骑手和全部商家账号(userType=1/2/3/4/5)统一使用 info_user.tel_phone。有效商家/骑手的 tel_phone 不得重复,软删除账号(del_flag!='0')不占用手机号;手机号按存储字符串精确比较,0912...+886... 视为不同号码。普通用户的 phone 可与商家/骑手的 tel_phone 相同。
  • FR-014: 商家/骑手手机号唯一性通过业务层校验实现,不新增数据库唯一索引。新增与修改时均校验,修改时排除当前 user_id
  • FR-015: LINE 登录成功后,line_userline_riderline_merchant 分别签发普通用户、骑手、商家 App 会话 token,并跳回对应 App scheme。

Key Entities

  • info_user_oauth(新增)iduser_idprovider(apple/google/line_user/line_rider/line_merchant)、provider_uidcreate_timeUNIQUE(provider, provider_uid) 用于按三方ID反查用户;user_id 普通索引。
  • InfoUser(已有,不改):仍是手机号为主键,无三方 ID 列。

安全要点

  • Apple/Google 必须校验 audience(= 我方 client_id/bundleId),防其他 App 的 token 被冒用。
  • Apple 校验 iss=https://appleid.apple.com + exp。
  • tempKey 一次性、短 TTL(5 分钟),防重放。

2026-09-08 增量:骑手、商家 Apple / Google 与用户端兼容

  • 新增 apple_riderapple_merchantgoogle_ridergoogle_merchant,各端独立校验 audience,不回退到用户端 client ID。
  • 骑手仅允许已有有效 userType=2,商家仅允许已有有效 userType=1/3/4/5;通过 tel_phone 验证绑定,不自动创建业务账号。子账号继续校验启用状态与归属权限。
  • 业务账号首次绑定要求真实短信验证码,不使用原用户分支的固定验证码兼容逻辑;用户原校验行为不变。
  • 按端签发 QS_TOKEN_KEY / SH_APP_TOKEN_KEY,用户原有 applegoogle 配置、绑定和 token 类型保持兼容。
  • 兼容用户 App 仍在使用的 provider=line 和不带 provider 的 /auth/line/callback,旧授权地址换 token 时使用原 redirect URI。line / line_user 均可读取旧、新绑定;不直接执行数据迁移。
  • 用户旧版不强制升级 state 协议;客户端升级与真实凭证验证须单独记录实际完成情况,不以单元测试代替上线验收。
  • 业务 LINE 新增 POST /auth/line/authorize 签发五分钟有效的 provider 绑定 state;回调和直接提交 code 均要求单次消费,App 比较回跳 state。用户旧 LINE 协议保持不变。

不在本期范围(原记录)

  • 后台管理端解绑/查看三方绑定(后续增量)。
  • 第三家以上三方(微信/Facebook)——表结构已可扩展,但本期只接 Apple/Google/LINE。
  • Apple 隐藏邮箱中转、refresh_token 续期等高级场景。