fix(auth): 微信OAuth服务工厂改为真单例,修复回调state必校验失败 (#1718) #1719
Reference in New Issue
Block a user
Delete Branch "fix/wechat-oauth-service-singleton-1718"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
背景
Issue #1718 配置微信登录环境变量后做端到端验证时发现:微信登录在真实凭证下完全不可用。
/api/v1/auth/wechat/url生成的 state 存在MemoryStateStore里,但get_wechat_oauth_service()名义上是单例工厂、实际每次调用都return WechatOAuthService()—— 每个请求拿到全新实例和全新 state store。微信回调/wechat/callback校验 state 时永远找不到,必返回 400「无效的 state 参数,请求可能已过期或被篡改」。此 bug 在 mock 模式下被掩盖(未配置时走 mock 分支,state 校验同样会失败,但前端联调可能直接用 mock 链路未暴露)。
修改
packages/application/auth/wechat_oauth_service.py:模块级_oauth_service_singleton懒加载单例,state store 跨请求共享;注释标明多实例部署需替换为 Redis storetests/unit/test_wechat_oauth_service.py:新增 2 个回归测试验证
注意
单容器单 uvicorn worker 下此修复即可;未来 API 多 worker 或多副本时,MemoryStateStore 需换成 Redis 实现(代码里已有 TODO)。
🚀 预览环境已部署
【阻塞级判定】
📊 审查概览
🔴 阻塞级问题(必须修复)
无
💡 改进建议(不阻塞合并)
if _oauth_service_singleton is None: ...在多线程环境下(如 gunicorn 多线程模式)存在竞态条件。虽然 Python 的 GIL 提供了一定程度的保护,但在WechatOAuthService()初始化过程中发生线程切换仍可能导致创建多个实例,从而引入 state 不共享的回归风险。import threading; _lock = threading.Lock())来确保实例化的原子性,或者使用functools.lru_cache装饰器来实现更简洁的线程安全单例。✅ 良好实践
test_state_survives_across_factory_calls非常出色,不仅验证了单例模式,还模拟了真实的业务场景(生成 URL -> 回调校验 -> 重放攻击防御),有效确保了修复的完整性。monkeypatch重置全局单例状态,避免了测试用例之间的相互干扰。✅ 格式检查通过 | ✅ 逻辑审查通过 | ✅ 性能良好
🤖 由 AI 代码审查机器人自动生成 | 2026-09-05 09:15:01 | 模型:
🗑️ 预览环境已清理
PR #1719 已关闭或合并,对应的预览环境已被清理。