# 骑手、商家快捷登录接入(2026-09-08) ## 兼容边界 用户端继续使用原 `apple`、`google`、`line` 或已升级的 `line_user`,请求/响应结构与用户会话不变。旧 LINE 回调 `/auth/line/callback` 不带 provider 时按旧用户渠道处理,换 token 使用不带 provider 的原地址;`line` 和 `line_user` 绑定均可读取。不得要求用户 App 同步发版或更换原 client ID。 本次新增渠道如下;首次只关联已有业务账号,不创建骑手或商家。 | App | Apple | Google | LINE | 手机号 | 会话 | |---|---|---|---|---|---| | 骑手 | apple_rider | google_rider | line_rider | tel_phone,userType=2 | QS_TOKEN_KEY | | 商家 | apple_merchant | google_merchant | line_merchant | tel_phone,userType=1/3/4/5 | SH_APP_TOKEN_KEY | ## Apple / Google 原生 SDK 取得 Apple identityToken 或 Google ID token 后: ```http POST /infouser/user/oauthLogin Content-Type: application/json {"provider":"apple_rider","credential":"","cid":"<设备推送标识>","cidType":"<原有类型>","deviceToken":"<设备token>","voIPToken":"<语音推送token>"} ``` Apple 首次授权时若凭证带用户共享姓名(`ASAuthorizationAppleIDCredential` 的 fullName 拼接),在同一请求追加可选字段 `"fullName":"<姓名>"`;后端验证通过后保存到该 Apple 绑定(2026-09-24 增量,供资料页展示第三方名称)。仅首次授权有值,后续登录不要求提交。 已绑定返回 `{code:200,msg,data,token}`,商家返回现有商家登录视图。未绑定返回 `{code:200,msg,data:{status:"needPhone",tempKey}}`,进入手机验证页。 绑定接口保持不变,端信息已保存在一次性 tempKey 中,禁止 App 自行指定角色或用户 ID: ```http POST /infouser/user/oauthBindPhone Content-Type: application/json {"tempKey":"<临时凭证>","phone":"<业务账号手机号>","code":"<短信验证码>","cid":"<设备推送标识>"} ``` 账号不存在时引导使用已有账号/联系管理员;不得在 OAuth 页面自动注册业务账号。业务账号必须验证真实短信码,不能使用固定测试码。tempKey 五分钟有效且单次消费,绑定失败须重新发起第三方登录。密码、手机号登录入口仍保留。 ## 业务 App LINE:先获取 state ```http POST /auth/line/authorize Content-Type: application/json {"provider":"line_rider"} ``` 返回 `{code:200,data:{authorizationUrl,state}}`。App 保存 state 并打开服务端返回的 authorizationUrl,不替换 redirect_uri 或 Channel ID。 - 骑手回调:`/auth/line/callback?provider=line_rider`,回跳 `com.twanmsdqs.app://pages/UserCenter/oauthLogin`。 - 商家回调:`/auth/line/callback?provider=line_merchant`,回跳 `com.twanmsdsj.app://pages/UserCenter/oauthLogin`。 - 服务端验证 state 属于当前 provider 且未过期/消费,再交换 code。成功/失败回跳都携带 state;App 必须先与本地发起值比较,不匹配时不得保存 token 或使用 tempKey。 - 已绑定:`?token=...&state=...`;未绑定:`?needPhone=1&tempKey=...&state=...`;失败/取消:`?error=...&state=...`。处理后清除本地 state,并防止重复处理同一个回跳。 - 若 App 在请求到服务端前拦截 code,则先校验回调 state,再调用 `/infouser/user/oauthLogin`,携带 `{provider,credential:code,state}`。只选择一种 code 消费路径,不能同时访问回调又提交 oauthLogin。 - 用户旧 LINE 登录不强制 state 新协议。本轮不改用户 App 的固定 state 或既有回跳处理。 按钮、取消、配置缺失、绑定失败等新增文案均须使用现有四语言 i18n。无 SDK 能力/配置时不得展示可点击但无法授权的入口。 ## 部署配置(不要写入客户端 Secret) | 环境变量 | 用途 | |---|---| | APPLE_RIDER_CLIENT_ID | 骑手 Apple identityToken 的 audience | | APPLE_MERCHANT_CLIENT_ID | 商家 Apple identityToken 的 audience | | GOOGLE_RIDER_CLIENT_ID | 骑手 Google ID token 的 audience(服务端 OAuth client ID) | | GOOGLE_MERCHANT_CLIENT_ID | 商家 Google ID token 的 audience(服务端 OAuth client ID) | | LINE_USER_CLIENT_SECRET | 现有用户 LINE Channel Secret,发布时保持有效配置 | | LINE_RIDER_CLIENT_SECRET | 骑手 LINE Channel Secret | | LINE_MERCHANT_CLIENT_SECRET | 商家 LINE Channel Secret | | LINE_USER_LEGACY_REDIRECT_URI | 旧用户 LINE 原授权地址,默认现有生产 `/auth/line/callback` | 四个新增 client ID 默认为空,缺失只拒绝对应新增渠道;不覆盖 `oauth.apple.client-id` / `oauth.google.client-id` 的原用户配置。Google client ID 应与 SDK 请求 ID token 所用值一致,不能直接把 Android 包名当作 OAuth client ID。 渠道校验依据:[Apple 身份校验](https://developer.apple.com/documentation/signinwithapple/verifying-a-user)、[Google 后端校验](https://developers.google.com/identity/sign-in/android/backend-auth)、[LINE 授权协议](https://developers.line.biz/en/docs/line-login/integrate-line-login/)。 ## 验收 1. 用户旧 App 的 Apple、Google、LINE:已绑定登录、首次绑定、退出重登;旧 LINE 无 provider 回调及旧绑定仍可用。 2. 骑手和普通商家/夜市/子账号分别完成三渠道首次绑定与重复登录;真实手机号验证码、无账号拒绝、停用账号拒绝、子账号归属失效拒绝。 3. 同一手机号同时有普通用户和业务账号时,各端登录后身份、token 和菜单权限正确;跨 App audience 与错误角色拒绝。 4. LINE state 缺失、过期、跨端、重复回调均拒绝;App 回跳 state 不匹配时不写入会话。 5. 未完成真实渠道和 App 验收前,不以本地自动化测试宣称功能已上线。