feat(#558): 微信登录 + 绑定手机号邮箱完整后端实现 #670

Merged
auto-approve-bot merged 6 commits from feat/558-wechat-login into develop 2026-07-21 09:21:02 +08:00
Owner

功能说明

微信登录 + 绑定手机号/邮箱 完整后端实现(#558)

数据库变更(migration 049)

  • users 表新增:phone / phone_verified / binding_completed_at 字段
  • 新建 verification_codes 表:统一管理邮箱+手机验证码

新增接口

  • GET /auth/wechat/url — 获取微信扫码登录授权链接
  • POST /auth/wechat/callback — 微信登录回调,返回 token + binding_complete 状态
  • POST /auth/send-verification-code — 发送验证码(手机/邮箱)
  • POST /auth/bind-contact — 绑定手机号和/或邮箱(需登录态)
  • GET /auth/me — 扩展返回 phone / phone_verified / binding_complete

核心模块

  • 微信OAuth服务:支持微信开放平台扫码登录,未配置时走 mock 模式方便联调
  • 验证码服务:统一生成/校验 + 60s 冷却 + 每日 10 次上限 + 5 次尝试错误锁定
  • 绑定用例:手机+邮箱同时绑定或单独绑定,校验唯一性 + 验证码有效性
  • 短信服务:Noop(开发用)+ 阿里云 SMS 适配器骨架

复用

  • 微信登录用户创建/查找复用现有 WechatSyncUseCase 逻辑
  • 已有 wechat_openid / wechat_unionid 字段直接用

测试

  • 单元测试 20 个全绿(手机/邮箱格式校验、验证码生成/校验/过期/频控、绑定流程、微信OAuth mock)
## 功能说明 微信登录 + 绑定手机号/邮箱 完整后端实现(#558) ## 数据库变更(migration 049) - users 表新增:phone / phone_verified / binding_completed_at 字段 - 新建 verification_codes 表:统一管理邮箱+手机验证码 ## 新增接口 - `GET /auth/wechat/url` — 获取微信扫码登录授权链接 - `POST /auth/wechat/callback` — 微信登录回调,返回 token + binding_complete 状态 - `POST /auth/send-verification-code` — 发送验证码(手机/邮箱) - `POST /auth/bind-contact` — 绑定手机号和/或邮箱(需登录态) - `GET /auth/me` — 扩展返回 phone / phone_verified / binding_complete ## 核心模块 - **微信OAuth服务**:支持微信开放平台扫码登录,未配置时走 mock 模式方便联调 - **验证码服务**:统一生成/校验 + 60s 冷却 + 每日 10 次上限 + 5 次尝试错误锁定 - **绑定用例**:手机+邮箱同时绑定或单独绑定,校验唯一性 + 验证码有效性 - **短信服务**:Noop(开发用)+ 阿里云 SMS 适配器骨架 ## 复用 - 微信登录用户创建/查找复用现有 WechatSyncUseCase 逻辑 - 已有 wechat_openid / wechat_unionid 字段直接用 ## 测试 - 单元测试 20 个全绿(手机/邮箱格式校验、验证码生成/校验/过期/频控、绑定流程、微信OAuth mock)
xiaoxia added 1 commit 2026-07-21 08:38:55 +08:00
feat(#558): 微信登录 + 绑定手机号邮箱完整后端实现
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 34s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m3s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m23s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 2m25s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m3s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m12s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 23s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 4m8s
AI Code Review / AI Code Review (pull_request) Successful in 5m38s
100e054896
- 数据库:users表加phone/phone_verified/binding_completed_at字段 + 新建verification_codes表(migration 049)
- 微信OAuth:GET /auth/wechat/url + POST /auth/wechat/callback,支持配置缺失时的mock模式
- 验证码服务:统一管理手机+邮箱验证码,60s冷却+每日10次+5次尝试错误频控
- 绑定接口:POST /auth/send-verification-code + POST /auth/bind-contact
- /me 接口扩展:返回 phone / phone_verified / binding_complete
- 短信服务:Noop + 阿里云适配器骨架
- 单元测试20个全绿

🚀 预览环境已部署

项目 详情
PR号 #670
预览链接 https://pr-670.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #670 | | 预览链接 | [https://pr-670.preview.xiaoxiajianji.com](https://pr-670.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
gitea-actions bot added 1 commit 2026-07-21 08:41:57 +08:00
xiaoxia added 1 commit 2026-07-21 08:57:18 +08:00
fix(#558): 清理未使用import,修复ruff检查
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 / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E 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 / Check if frontend-only change (pull_request) Successful in 29s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m19s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m23s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 1m57s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m32s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m34s
AI Code Review / AI Code Review (pull_request) Successful in 2m52s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 29s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m24s
54e04302cf
xiaoxia added 1 commit 2026-07-21 09:07:16 +08:00
fix(#558): migration幂等处理,phone字段已在029中存在
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 / 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 / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 23s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m30s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m32s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 2m2s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m30s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m29s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m32s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m49s
AI Code Review / AI Code Review (pull_request) Successful in 5m41s
d594a7a273
xiaoxia force-pushed feat/558-wechat-login from 601386a460 to d594a7a273 2026-07-21 09:07:16 +08:00 Compare
gitea-actions bot added 1 commit 2026-07-21 09:09:44 +08:00
xiaoxia added 1 commit 2026-07-21 09:15:47 +08:00
fix(#558): black格式化
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 / Deploy Staging (Watchtower auto-deploy) (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 / 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 / Check if frontend-only change (pull_request) Successful in 32s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m21s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m35s
AI Code Review / AI Code Review (pull_request) Successful in 3m39s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Successful in 3m38s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m12s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m49s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 5m14s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 30s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m10s
f5574c2407
Collaborator

代码审查结果 - PR #670

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

  1. apps/api/app/api/routes/auth.py 第447行 & 第490行:数据库连接泄漏风险

    • 问题描述:在 send_verification_codebind_contact 函数中,使用 db = next(get_db()) 手动获取数据库会话。如果 get_db 是标准的生成器依赖项(包含 try...finally: db.close()),直接调用 next() 而不耗尽或关闭生成器,会导致 finally 块不执行,从而造成数据库连接无法释放,最终耗尽连接池。
    • 修改建议:应通过 FastAPI 的依赖注入系统 Depends(get_db) 来获取会话,或者显式管理生成器的生命周期(如使用 contextlib.closing 或 try-finally 块手动关闭)。
  2. packages/adapters/sqlalchemy_impl/verification_code_repository.py 第30行:事务原子性被破坏

    • 问题描述save 方法中直接调用了 self.session.commit()。在业务逻辑(UseCase)中,如果先保存验证码(提交),后续操作(如更新用户信息)失败,验证码记录已无法回滚,导致数据不一致(产生了“幽灵”验证码)。Repository 层通常不应负责事务提交,应由上层控制。
    • 修改建议:移除 save 方法中的 commit(),改为 flush(),或者在路由/用例层统一管理事务提交。
  3. packages/adapters/in_memory/user_repository.py 第30-41行:索引更新逻辑错误

    • 问题描述:在 save 方法中,当用户更新 phonewechat_openid 等字段时,代码直接向索引字典添加新映射,但未删除旧值的映射。例如用户将手机号从 A 改为 B,索引中会同时存在 A->userB->user。若此时有新用户尝试绑定手机号 A,系统会错误地返回旧用户,导致数据冲突。
    • 修改建议:在更新索引前,需先检查并移除该用户 ID 在旧值(如旧手机号)下的索引映射。
  4. packages/adapters/sms/sms_service.py 第20行:敏感信息泄露风险

    • 问题描述NoopSmsService.send_verification_code 使用 logger.info 打印了验证码 code。在生产环境或测试日志中泄露验证码属于安全隐患。
    • 修改建议:日志中应避免打印完整的验证码,或仅在开发环境且明确标识为测试数据时打印,建议打印脱敏信息(如 ****89)。

💡 建议(2个可选)

  1. apps/api/app/api/routes/auth.py 第265行 & 第328行:代码重复

    • 建议描述binding_complete 的计算逻辑在 get_current_user_infowechat_callback 中完全重复。建议将其提取为 User 实体的一个属性方法(如 user.is_binding_complete)或独立的辅助函数,以确保逻辑一致性并减少维护成本。
  2. apps/api/app/api/routes/auth.py 第514行:数据访问方式不健壮

    • 建议描述bind_contact 中使用 response.to_dict()["user"] 访问数据。如果 to_dict() 的结构发生变化或缺少 "user" 键,将引发 KeyError。建议直接访问对象属性或使用 .get("user") 进行安全访问。

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


🤖 由 AI 代码审查机器人自动生成 | 2026-07-21 09:19:25 | 模型:

## 代码审查结果 - PR #670 ### ⚠️ 问题(4个需要修改) 1. **apps/api/app/api/routes/auth.py 第447行 & 第490行**:数据库连接泄漏风险 - **问题描述**:在 `send_verification_code` 和 `bind_contact` 函数中,使用 `db = next(get_db())` 手动获取数据库会话。如果 `get_db` 是标准的生成器依赖项(包含 `try...finally: db.close()`),直接调用 `next()` 而不耗尽或关闭生成器,会导致 `finally` 块不执行,从而造成数据库连接无法释放,最终耗尽连接池。 - **修改建议**:应通过 FastAPI 的依赖注入系统 `Depends(get_db)` 来获取会话,或者显式管理生成器的生命周期(如使用 `contextlib.closing` 或 try-finally 块手动关闭)。 2. **packages/adapters/sqlalchemy_impl/verification_code_repository.py 第30行**:事务原子性被破坏 - **问题描述**:`save` 方法中直接调用了 `self.session.commit()`。在业务逻辑(UseCase)中,如果先保存验证码(提交),后续操作(如更新用户信息)失败,验证码记录已无法回滚,导致数据不一致(产生了“幽灵”验证码)。Repository 层通常不应负责事务提交,应由上层控制。 - **修改建议**:移除 `save` 方法中的 `commit()`,改为 `flush()`,或者在路由/用例层统一管理事务提交。 3. **packages/adapters/in_memory/user_repository.py 第30-41行**:索引更新逻辑错误 - **问题描述**:在 `save` 方法中,当用户更新 `phone`、`wechat_openid` 等字段时,代码直接向索引字典添加新映射,但未删除旧值的映射。例如用户将手机号从 A 改为 B,索引中会同时存在 `A->user` 和 `B->user`。若此时有新用户尝试绑定手机号 A,系统会错误地返回旧用户,导致数据冲突。 - **修改建议**:在更新索引前,需先检查并移除该用户 ID 在旧值(如旧手机号)下的索引映射。 4. **packages/adapters/sms/sms_service.py 第20行**:敏感信息泄露风险 - **问题描述**:`NoopSmsService.send_verification_code` 使用 `logger.info` 打印了验证码 `code`。在生产环境或测试日志中泄露验证码属于安全隐患。 - **修改建议**:日志中应避免打印完整的验证码,或仅在开发环境且明确标识为测试数据时打印,建议打印脱敏信息(如 `****89`)。 ### 💡 建议(2个可选) 1. **apps/api/app/api/routes/auth.py 第265行 & 第328行**:代码重复 - **建议描述**:`binding_complete` 的计算逻辑在 `get_current_user_info` 和 `wechat_callback` 中完全重复。建议将其提取为 `User` 实体的一个属性方法(如 `user.is_binding_complete`)或独立的辅助函数,以确保逻辑一致性并减少维护成本。 2. **apps/api/app/api/routes/auth.py 第514行**:数据访问方式不健壮 - **建议描述**:`bind_contact` 中使用 `response.to_dict()["user"]` 访问数据。如果 `to_dict()` 的结构发生变化或缺少 "user" 键,将引发 KeyError。建议直接访问对象属性或使用 `.get("user")` 进行安全访问。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ✅ 性能无明显问题 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-07-21 09:19:25 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
auto-approve-bot approved these changes 2026-07-21 09:19:59 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-07-21 09:19:59 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot merged commit 269723ced2 into develop 2026-07-21 09:21:02 +08:00
auto-approve-bot deleted branch feat/558-wechat-login 2026-07-21 09:21:02 +08:00

🗑️ 预览环境已清理

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

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

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