fix(web): 修复微信回调页token时序bug - 先存token再取用户信息 #764

Merged
xiaoxia merged 4 commits from fix/wechat-callback-token-order into develop 2026-07-23 19:35:46 +08:00
Owner

问题

WechatCallback页面存在与#734相同的时序bug:

getCurrentUser()setAuth() 之前执行,apiClient 请求拦截器从 localStorage 读不到 token,请求不带 Authorization header → 后端返回 401 → 触发响应拦截器登出逻辑 → 跳回登录页。

根因

#734 只修复了 useAuth.ts 里的 useLoginuseWechatCallback hook,但 WechatCallback.tsx 页面没有复用 hook,自己实现了一遍登录逻辑,漏掉了 token 存储时序的修复。

修复

#734 修复方式一致:

  1. 先手动把 access_token 和 refresh_token 存到 localStorage
  2. 再调用 getCurrentUser()(这时候拦截器能拿到 token 了)
  3. 最后 setAuth 同步 store 状态

改动

  • 1个文件:apps/web/src/pages/auth/WechatCallback.tsx
  • +7/-1

关联: #558, #734

## 问题 WechatCallback页面存在与#734相同的时序bug: `getCurrentUser()` 在 `setAuth()` 之前执行,apiClient 请求拦截器从 localStorage 读不到 token,请求不带 Authorization header → 后端返回 401 → 触发响应拦截器登出逻辑 → 跳回登录页。 ## 根因 #734 只修复了 `useAuth.ts` 里的 `useLogin` 和 `useWechatCallback` hook,但 `WechatCallback.tsx` 页面没有复用 hook,自己实现了一遍登录逻辑,漏掉了 token 存储时序的修复。 ## 修复 与 #734 修复方式一致: 1. 先手动把 access_token 和 refresh_token 存到 localStorage 2. 再调用 getCurrentUser()(这时候拦截器能拿到 token 了) 3. 最后 setAuth 同步 store 状态 ## 改动 - 1个文件:`apps/web/src/pages/auth/WechatCallback.tsx` - +7/-1 关联: #558, #734
xiaoxia added 1 commit 2026-07-23 18:29:56 +08:00
fix(web): 修复微信回调页token时序bug - 先存token再取用户信息
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m2s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 37s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m15s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m46s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 3m33s
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 26s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 53s
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 3m8s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 5m9s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 10m35s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 47m10s
ee916acb1b
WechatCallback页面存在与#734相同的时序问题:
getCurrentUser()在setAuth()之前执行,导致请求拦截器
从localStorage取不到token,返回401后触发登出逻辑跳回登录页。

修复方式与#734一致:先手动存token到localStorage,
再调用getCurrentUser(),最后setAuth同步store状态。

关联: #558, #734
auto-approve-bot approved these changes 2026-07-23 18:34:13 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-07-23 18:34:14 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
xiaoxia added 1 commit 2026-07-23 18:56:25 +08:00
test(web): 添加WechatCallback页面基础单元测试
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 53s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 47s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 28s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 3m40s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m58s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 53s
AI Code Review / AI Code Review (pull_request) Successful in 3m56s
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 13s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 6m47s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 29s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 49m12s
2f237c80cf
xiaoxia added 1 commit 2026-07-23 19:14:45 +08:00
test(web): 修复WechatCallback测试 - mock正确的code/state参数
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 10s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 37s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 56s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m4s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m51s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m40s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 46s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 4m56s
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 10s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 2m33s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 15s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 47m8s
375692e838
xiaoxia added 1 commit 2026-07-23 19:21:52 +08:00
test(web): 修复WechatCallback测试 - mock localStorage的wechat_state
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 12s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 32s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m23s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m23s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m8s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 3m5s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 44s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m35s
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 15s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 15s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 3m13s
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 8m42s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 12s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 47m2s
5bf572b225
Collaborator

代码审查结果 - PR #764

⚠️ 问题(2个需要修改)

  1. apps/web/src/pages/auth/WechatCallback.tsx 第42-46行:状态同步风险,异常情况下会导致状态不一致。

    • 原因:代码在调用 getCurrentUser() 之前手动将 token 写入 localStorage。如果 getCurrentUser() 请求失败(如网络错误或 401),代码抛出异常或进入 catch 块,导致后续的 setAuth() 未执行。此时 localStorage 中残留了 token,但 AuthStore 中的用户状态未更新,造成“有 Token 但未登录”的僵尸状态。
    • 后果:后续请求拦截器可能读取到残留 token 发起请求,但应用内状态显示未登录,导致业务逻辑混乱。
    • 建议:将 localStorage.setItem 的逻辑移至 setAuth 函数内部统一管理,或者确保在 catch 块中清除已写入的 token。
  2. apps/web/src/test/pages/auth/WechatCallback.test.tsx 第16行:测试覆盖率不足,核心逻辑未被验证。

    • 原因:Mock 函数 wechatCallback 返回了一个永远 pending 的 Promise (new Promise(() => {}))。这导致测试仅停留在 Loading 状态,本次 PR 新增的“手动写入 Token”和“调用 getCurrentUser”的关键逻辑路径从未被执行。
    • 后果:无法验证新增代码是否正确运行,甚至无法发现潜在的运行时错误。
    • 建议:增加测试用例,模拟 wechatCallback 成功 resolve 的情况,验证 localStorage.setItem 是否被正确调用以及 getCurrentUser 是否被触发。

💡 建议(1个可选)

  1. apps/web/src/pages/auth/WechatCallback.tsx 第41行:架构设计建议。
    • 内容:注释提到“让请求拦截器能拿到”,说明请求拦截器强依赖 localStorage。这属于副作用依赖,建议重构请求拦截器,使其直接从 AuthStore(内存状态)读取 Token,从而避免在业务代码中手动同步 localStorage,降低状态管理复杂度。

格式检查通过 | 逻辑审查需修改 | 性能无问题


🤖 由 AI 代码审查机器人自动生成 | 2026-07-23 11:28:03 | 模型:

## 代码审查结果 - PR #764 ### ⚠️ 问题(2个需要修改) 1. **apps/web/src/pages/auth/WechatCallback.tsx 第42-46行**:状态同步风险,异常情况下会导致状态不一致。 - **原因**:代码在调用 `getCurrentUser()` 之前手动将 token 写入 `localStorage`。如果 `getCurrentUser()` 请求失败(如网络错误或 401),代码抛出异常或进入 catch 块,导致后续的 `setAuth()` 未执行。此时 `localStorage` 中残留了 token,但 AuthStore 中的用户状态未更新,造成“有 Token 但未登录”的僵尸状态。 - **后果**:后续请求拦截器可能读取到残留 token 发起请求,但应用内状态显示未登录,导致业务逻辑混乱。 - **建议**:将 `localStorage.setItem` 的逻辑移至 `setAuth` 函数内部统一管理,或者确保在 `catch` 块中清除已写入的 token。 2. **apps/web/src/test/pages/auth/WechatCallback.test.tsx 第16行**:测试覆盖率不足,核心逻辑未被验证。 - **原因**:Mock 函数 `wechatCallback` 返回了一个永远 pending 的 Promise (`new Promise(() => {})`)。这导致测试仅停留在 Loading 状态,本次 PR 新增的“手动写入 Token”和“调用 getCurrentUser”的关键逻辑路径从未被执行。 - **后果**:无法验证新增代码是否正确运行,甚至无法发现潜在的运行时错误。 - **建议**:增加测试用例,模拟 `wechatCallback` 成功 resolve 的情况,验证 `localStorage.setItem` 是否被正确调用以及 `getCurrentUser` 是否被触发。 ### 💡 建议(1个可选) 1. **apps/web/src/pages/auth/WechatCallback.tsx 第41行**:架构设计建议。 - **内容**:注释提到“让请求拦截器能拿到”,说明请求拦截器强依赖 `localStorage`。这属于副作用依赖,建议重构请求拦截器,使其直接从 AuthStore(内存状态)读取 Token,从而避免在业务代码中手动同步 `localStorage`,降低状态管理复杂度。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ✅ 性能无问题 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-07-23 11:28:03 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia merged commit 5629cf63ec into develop 2026-07-23 19:35:46 +08:00

🗑️ 预览环境已清理

PR #764 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #764 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.