11 KiB
11 KiB
微信登录真实联调手册
日期:2026-04-21
1. 文档目的
这份文档用于把当前仓库里的微信登录,从“代码已具备 mock / real 双模式”推进到“开发、测试、部署都能按步骤联调”的级别。
文档目标不是重复实现设计,而是回答以下落地问题:
- 本地先怎么用 mock 跑通
- 什么时候切
real - 真实微信开放平台需要配什么
- 回调地址到底怎么拼
- 前后端各自怎么验证
- 失败时先查哪一层
2. 当前实现结论
当前仓库里的微信登录实现固定为两段式:
- 微信 OAuth 只负责返回第三方身份:
code -> openid / unionid - Rust
api-server负责把该第三方身份换成本系统 JWT
因此当前正式口径固定为:
- 前端不直接消费微信 token
SpacetimeDB未来也不直接消费微信 token- 统一由
api-server签发系统 JWT,再回给前端和后续服务层
3. 模式说明
3.1 mock 模式
适用场景:
- 本地前后端先验证交互链路
- 还没有微信开放平台配置
- 还没有可用公网回调域名
当前配置:
WECHAT_AUTH_ENABLED="true"
WECHAT_AUTH_PROVIDER="mock"
WECHAT_CALLBACK_PATH="/api/auth/wechat/callback"
WECHAT_REDIRECT_PATH="/"
WECHAT_MOCK_USER_ID="wx-mock-user"
WECHAT_MOCK_UNION_ID="wx-mock-union"
WECHAT_MOCK_DISPLAY_NAME="微信旅人"
WECHAT_MOCK_AVATAR_URL=""
mock 模式行为固定为:
GET /api/auth/wechat/start仍会创建一次性state- 返回的
authorizationUrl不会跳去微信,而是直接指向本地 callback - callback 会走 mock 身份:
mock_code + state - 后端仍会完整创建微信登录态、refresh session 与待绑定账号
3.2 real 模式
适用场景:
- 已拿到微信开放平台应用
- 已有可访问的公网域名
- 已在微信开放平台后台配置回调域名
当前配置:
WECHAT_AUTH_ENABLED="true"
WECHAT_AUTH_PROVIDER="real"
WECHAT_APP_ID="你的微信开放平台 AppID"
WECHAT_APP_SECRET="你的微信开放平台 AppSecret"
WECHAT_CALLBACK_PATH="/api/auth/wechat/callback"
WECHAT_REDIRECT_PATH="/"
real 模式行为固定为:
GET /api/auth/wechat/start返回微信真实授权地址- 用户在微信侧完成授权
- 微信回跳到
WECHAT_CALLBACK_PATH - 后端用
code换access_token/openid/unionid - 后端签发本系统 JWT,并把结果通过 URL hash 回跳给前端
4. 环境变量清单
当前真实联调至少需要这些变量:
| 变量 | 必填 | 说明 |
|---|---|---|
WECHAT_AUTH_ENABLED |
是 | 是否启用微信登录 |
WECHAT_AUTH_PROVIDER |
是 | mock 或 real |
WECHAT_APP_ID |
real 模式必填 |
微信开放平台应用 ID |
WECHAT_APP_SECRET |
real 模式必填 |
微信开放平台应用 Secret |
WECHAT_CALLBACK_PATH |
是 | 回调路径,默认 /api/auth/wechat/callback |
WECHAT_REDIRECT_PATH |
是 | 登录完成后前端默认落点 |
WECHAT_AUTHORIZE_ENDPOINT |
否 | 默认桌面二维码授权地址 |
WECHAT_ACCESS_TOKEN_ENDPOINT |
否 | 默认 access_token 接口 |
WECHAT_USER_INFO_ENDPOINT |
否 | 默认用户信息接口 |
WECHAT_JS_CODE_SESSION_ENDPOINT |
否 | 默认小程序 jscode2session 接口 |
WECHAT_MINI_PROGRAM_APP_ID |
小程序 real 模式必填 |
微信小程序 AppID;不填时回退 WECHAT_APP_ID |
WECHAT_MINI_PROGRAM_APP_SECRET |
小程序 real 模式必填 |
微信小程序 AppSecret;不填时回退 WECHAT_APP_SECRET |
WECHAT_STATE_TTL_MINUTES |
否 | state 有效期,默认 15 分钟 |
补充说明:
WECHAT_CALLBACK_PATH只是路径,不是完整 URL。- 当前完整回调地址由后端在运行时按请求头拼接:
- 优先
x-forwarded-proto - 其次
host/x-forwarded-host
- 优先
- 因此部署到反向代理后,代理层必须正确透传
host与x-forwarded-proto。
5. 微信开放平台后台配置
真实联调前,需要先在微信开放平台完成以下配置:
- 创建网站应用并拿到
AppID / AppSecret - 配置网站授权回调域名
- 确保回调域名与实际访问域名一致
当前项目必须特别注意:
- 微信后台通常配置的是“域名”,不是完整路径
- 但项目真正收到回调时会落到:
https://你的域名/api/auth/wechat/callback
- 如果代理层把 HTTPS 终止在上游网关,必须把
x-forwarded-proto=https正确传给api-server - 否则后端可能生成
http://.../api/auth/wechat/callback,导致微信侧回调地址不匹配
6. 本地 mock 联调步骤
6.1 配置
在 .env.local 中写入:
SMS_AUTH_ENABLED="true"
WECHAT_AUTH_ENABLED="true"
WECHAT_AUTH_PROVIDER="mock"
VITE_AUTH_ALLOW_DEV_GUEST="false"
6.2 启动
前端和后端分别启动当前项目自己的开发链路。
若只验证 Rust 后端,可直接启动 server-rs 的 api-server。
6.3 验证顺序
- 请求
GET /api/auth/login-options - 期望返回同时包含:
phonewechat
- 前端点击“微信登录”
- 浏览器应先跳到
/api/auth/wechat/start - 随后直接命中本地
/api/auth/wechat/callback?... - 前端收到 hash:
auth_provider=wechatauth_token=...auth_binding_status=pending_bind_phone
- 页面进入“绑定手机号”界面
- 发送验证码并绑定手机号
- 若手机号未使用,当前账号激活
- 若手机号已对应正式账号,微信身份并入已有正式账号
7. 真实微信联调步骤
7.1 切换配置
在 .env.local 中切到:
SMS_AUTH_ENABLED="true"
WECHAT_AUTH_ENABLED="true"
WECHAT_AUTH_PROVIDER="real"
WECHAT_APP_ID="你的 AppID"
WECHAT_APP_SECRET="你的 AppSecret"
WECHAT_CALLBACK_PATH="/api/auth/wechat/callback"
WECHAT_REDIRECT_PATH="/"
VITE_AUTH_ALLOW_DEV_GUEST="false"
7.2 部署要求
需要有一个用户浏览器能够访问的地址,例如:
https://game.example.com
并且该地址最终把认证请求转发到当前 Rust api-server。
7.3 代理层要求
反向代理必须至少透传:
HostX-Forwarded-ProtoX-Forwarded-Host(如果你的代理链路会改写 Host)
7.4 验证顺序
- 浏览器访问前端页面
- 点击“微信登录”
- 观察
/api/auth/wechat/start返回的authorizationUrl - 确认其中
redirect_uri指向真实回调地址 - 在微信授权完成后,确认请求回到:
/api/auth/wechat/callback?code=...&state=...
- 观察回跳前端地址是否带上:
auth_provider=wechatauth_token=...auth_binding_status=active|pending_bind_phone
- 如果进入待绑定页面,继续完成手机号绑定
- 绑定后再请求
GET /api/auth/me - 确认:
- 当前用户存在
wechatBound = truebindingStatus已更新为目标状态
8. 小程序 web-view 登录联调步骤
小程序壳走原生 wx.login,不走网页 OAuth callback。联调前需要额外确认:
WECHAT_AUTH_ENABLED=true
WECHAT_AUTH_PROVIDER=real
WECHAT_MINI_PROGRAM_APP_ID="你的微信小程序 AppID"
WECHAT_MINI_PROGRAM_APP_SECRET="你的微信小程序 AppSecret"
在 miniprogram/config.js 中确认:
const WEB_VIEW_ENTRY_URL = 'https://你的H5业务域名/';
const API_BASE_URL = 'https://你的服务器域名/';
const MINI_PROGRAM_APP_ID = '你的微信小程序 AppID';
联调流程:
- 微信开发者工具打开项目根目录。
- 小程序启动后调用
wx.login。 - 小程序壳请求:
POST /api/auth/wechat/miniprogram-login
- 后端通过
jscode2session兑换openid/unionid。 - 后端返回系统
token、bindingStatus与user。 - 小程序壳打开 H5,并在 hash 中附加:
auth_provider=wechatauth_token=...auth_binding_status=active|pending_bind_phone
- H5 消费 hash 后通过
/api/auth/me恢复登录态。
这里不能把裸 openid 作为 web-view query 登录凭证;openid 只能留在后端身份绑定层,H5 只消费本系统 JWT。
9. 账号命中规则
当前实现固定按以下顺序命中已有账号:
- 先按
unionid - 再按
openid - 都没有命中时,创建
pending_bind_phone微信壳账号
补充规则:
- 若按
unionid命中了已有微信身份,但本次微信回调带来了新的openid,后端会把新的openid -> user_id映射补齐 - 若后续绑定手机号时发现该手机号已经属于正式账号,则会把微信身份并入这个正式账号
10. 前端验收点
前端联调时至少检查以下行为:
- 登录弹窗只在
login-options返回wechat时显示“微信登录”按钮 - 点击微信登录后应跳去后端返回的
authorizationUrl - 回调 hash 被前端消费后,应把
auth_token存入本地登录态 - 若
auth_binding_status=pending_bind_phone,页面必须进入绑定手机号界面 - 绑定成功后,应切回正常已登录状态
10. 后端验收点
当前后端至少应满足以下检查:
GET /api/auth/wechat/start能返回授权地址GET /api/auth/wechat/callback能创建系统会话并回跳POST /api/auth/wechat/bind-phone能完成补绑GET /api/auth/me能反映最新bindingStatus / wechatBound- access token claims 中的
provider应保持当前会话来源为wechat
11. 常见失败点
11.1 点微信登录后直接报“微信登录暂未启用”
先检查:
WECHAT_AUTH_ENABLED是否为true- 运行的是否真是 Rust
api-server - 前端是否还在打旧 Node 服务
11.2 微信授权页能打开,但回调报错
先检查:
- 微信后台配置的回调域名是否正确
- 代理层是否正确透传
host与x-forwarded-proto WECHAT_CALLBACK_PATH是否与当前代码路径一致
11.3 按 unionid 命中后又出现新壳账号
先检查:
- 微信开放平台当前应用是否真的能返回稳定
unionid - 当前账号历史上是否只有
openid没有unionid - 是否发生了不同开放平台主体之间的数据割裂
11.4 绑定手机号后命中了已有正式账号,但前端看到 loginMethod=phone
这是当前实现允许的结果。
原因是:
- 返回的是目标正式账号快照
- 目标正式账号本身的主登录方式仍可能是
phone - 但当前会话签发的 access token
provider仍然是wechat
12. 当前自动化验证证据
当前仓库里已经有这些自动化验证:
cargo test -p api-server覆盖:wechat/startwechat/callbackwechat/bind-phone
cargo test -p module-auth覆盖:unionid优先命中已有微信用户- 微信待绑定账号并入已有手机号正式账号
npm test -- --run src/services/authService.test.ts覆盖:- 前端微信登录起跳
- callback hash 消费
13. 一句话切换原则
本地先用 mock 跑通页面和会话闭环,公网域名与微信后台配置就绪后,再切 real 做真实 OAuth 联调。