feat: support mini program phone authorization binding

This commit is contained in:
2026-05-12 22:30:24 +08:00
parent 26139f80d3
commit e36a562098
17 changed files with 657 additions and 31 deletions

View File

@@ -6,12 +6,13 @@
本次先用微信小程序 `web-view` 承载现有 H5不重写 React/Vite 主前端,也不把 SpacetimeDB SDK 或业务规则搬进小程序端。
当前小程序壳只承担件事:
当前小程序壳只承担件事:
1. 提供微信开发者工具可识别的 `miniprogram/` 工程根目录。
2. 在原生小程序壳中调用 `wx.login` 获取小程序 `code`
3. 调用服务器域名下的 `/api/auth/wechat/miniprogram-login`,由 Rust `api-server` 兑换微信身份并签发系统登录态。
4. 用一个全屏 `web-view` 打开现有 H5 入口,并把系统 `auth_token` 放入 H5 现有登录回调 hash
4. 若后端返回 `pending_bind_phone`,先在小程序原生层通过 `button open-type="getPhoneNumber"` 取得用户同意后的手机号动态令牌,再调用 `/api/auth/wechat/bind-phone` 完成绑定
5. 用一个全屏 `web-view` 打开现有 H5 入口,并把系统 `auth_token` 放入 H5 现有登录回调 hash。
重要边界:
@@ -56,6 +57,9 @@ WECHAT_AUTH_ENABLED=true
WECHAT_AUTH_PROVIDER=real
WECHAT_MINI_PROGRAM_APP_ID="你的微信小程序 AppID"
WECHAT_MINI_PROGRAM_APP_SECRET="你的微信小程序 AppSecret"
WECHAT_JS_CODE_SESSION_ENDPOINT="https://api.weixin.qq.com/sns/jscode2session"
WECHAT_STABLE_ACCESS_TOKEN_ENDPOINT="https://api.weixin.qq.com/cgi-bin/stable_token"
WECHAT_PHONE_NUMBER_ENDPOINT="https://api.weixin.qq.com/wxa/business/getuserphonenumber"
```
如果开放平台网页 OAuth 与小程序使用同一个 AppID/Secret也可以继续使用已有
@@ -110,13 +114,28 @@ Content-Type: application/json
- 再按 `openid` 命中已有身份
- 都没有命中时创建 `pending_bind_phone` 的微信壳账号
6. `api-server` 签发系统 access token并写入 refresh session。
7. 小程序壳打开:
7. 如果返回 `bindingStatus=active`小程序壳打开:
```text
https://你的H5业务域名/#auth_provider=wechat&auth_token=<系统JWT>&auth_binding_status=active|pending_bind_phone
https://你的H5业务域名/#auth_provider=wechat&auth_token=<系统JWT>&auth_binding_status=active
```
8. H5 复用 `consumeAuthCallbackResult()` 消费 `auth_token` 并进入现有登录态恢复流程。
8. 如果返回 `bindingStatus=pending_bind_phone`,小程序壳暂不打开 H5而是展示原生 `getPhoneNumber` 按钮。用户点击并同意后,小程序把 `bindgetphonenumber` 事件里的 `detail.code` 作为 `wechatPhoneCode` 传给:
```http
POST /api/auth/wechat/bind-phone
Authorization: Bearer <JWT>
Content-Type: application/json
{
"wechatPhoneCode": "getPhoneNumber code"
}
```
9. `api-server` 通过微信 `stable_token` 获取小程序 `access_token`,再调用 `getuserphonenumber` 换取平台验证后的手机号,并复用现有微信待绑定账号合并逻辑。成功后重新签发 `active` 系统 token。
10. H5 复用 `consumeAuthCallbackResult()` 消费 `auth_token` 并进入现有登录态恢复流程。
补充H5 里的旧短信验证码绑定页继续保留为非小程序环境兜底;小程序原生手机号授权只替代“手动输入手机号 + 短信验证码”这一步,不代表后台静默读取本机号码。
## 5. 微信后台配置
@@ -153,7 +172,8 @@ npm run check:wechat-miniprogram-auth
1. 静态确认 `miniprogram/pages/web-view/index.js` 会请求 `/api/auth/wechat/miniprogram-login`,携带 `mini_program / wechat_mini_program` 客户端来源头,并把 `auth_provider/auth_token/auth_binding_status` 拼入 H5 hash。
2. 运行 `api-server` 定向测试 `wechat_miniprogram_login_returns_system_token_and_marks_session_source`,断言小程序登录返回 `token/bindingStatus/user`、写入 refresh cookie并且 `/api/auth/sessions` 能看到 `clientType=mini_program``clientRuntime=wechat_mini_program``miniProgramAppId`
3. 运行前端 `authService` 定向测试,断言 `consumeAuthCallbackResult()` 会消费 `#auth_provider=wechat&auth_token=...&auth_binding_status=...`、保存 access token并清理地址栏 hash
3. 静态确认小程序壳在 `pending_bind_phone` 时使用 `getPhoneNumber``wechatPhoneCode` 调用 `/api/auth/wechat/bind-phone`,而不是打开 H5 后再要求手输手机号
4. 运行前端 `authService` 定向测试,断言 `consumeAuthCallbackResult()` 会消费 `#auth_provider=wechat&auth_token=...&auth_binding_status=...`、保存 access token并清理地址栏 hash。
手工联调仍按以下口径确认真实微信与域名配置:
@@ -161,6 +181,7 @@ npm run check:wechat-miniprogram-auth
2. 未填写 `WEB_VIEW_ENTRY_URL``API_BASE_URL` 时,页面显示配置提示,不出现空白页。
3. 填写已配置业务域名后,小程序先请求 `/api/auth/wechat/miniprogram-login`
4. 后端返回 `token/bindingStatus/user`,并写入 refresh cookie。
5. 首页全屏打开 H5URL hash 中包含 `auth_provider=wechat``auth_token``auth_binding_status`
6. H5 内 `consumeAuthCallbackResult()` 消费 hash 后,`/api/auth/me` 能返回当前用户
7. `/api/auth/sessions` 能看到来源为 `mini_program / wechat_mini_program` 的会话记录。
5. 若返回 `pending_bind_phone`,先看到小程序原生授权手机号按钮;用户同意后,小程序请求 `/api/auth/wechat/bind-phone` 且请求体包含 `wechatPhoneCode`
6. 绑定成功后首页全屏打开 H5URL hash 中包含 `auth_provider=wechat``auth_token``auth_binding_status=active`
7. H5 内 `consumeAuthCallbackResult()` 消费 hash 后,`/api/auth/me` 能返回当前用户。
8. `/api/auth/sessions` 能看到来源为 `mini_program / wechat_mini_program` 的会话记录。