feat(user): 用户认证模块——注册/登录/JWT/验证码/限流 - #149
Conversation
- Add backend/Dockerfile with multi-stage build (uv + Python 3.12) - Add docker-compose.yml with backend and PostgreSQL services - Add db/init.sql for automatic database table initialization - Add .env.example with configuration template - PostgreSQL configured with port 7856 and secure password
…browser 三处让部署跑不起来的问题,都在这台服务器上实测定位: 1. 构建阶段 uv sync 超时。宿主机访问 pypi.org 需 8s,构建容器内默认超时会在 下载大包(uvloop)时 "operation timed out" 直接失败。改走国内镜像源并把 UV_HTTP_TIMEOUT 拉到 180s。 2. 容器起来即反复重启,报 "exec /app/.venv/bin/uvicorn: no such file or directory"。 文件其实存在,报的是它 shebang 指向的解释器——uv 装出来的 venv 里 shebang 与 .pth 都是绝对路径,builder 在 /build、runtime 在 /app,跨路径拷贝后解释器与 workspace 包全部失效。把 builder 的 WORKDIR 也改成 /app 即可。 3. 七牛上传 TLS 握手超时、媒体上传请求挂死。宿主机网卡 MTU 1480,而 compose 自建网络不继承 daemon 的 mtu 设置、默认仍是 1500,大包被丢。显式给网络设 1450 后,up-z0.qiniup.com 从握手超时 14s 变为 1.0s,上传恢复正常。 4. 浏览器跨域被全部拦下:OPTIONS 预检返回 405、响应无 access-control-* 头, 后端日志里连请求都看不到。挂上 CORSMiddleware,允许来源用 WINDUP_CORS_ORIGINS 覆盖,并放行 Vercel 预览域名。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
后端验证码/refresh_token 依赖 Redis,原 compose 只有 Postgres。 新增 redis:7-alpine 服务(含健康检查),backend depends_on 等待就绪, 环境变量 REDIS_URL=redis://redis:6379/0。
ORM 声明了 UniqueConstraint(user_id, project_name),但 init.sql 建表时遗漏。 生产 Postgres 并发创建同名项目不会触发 IntegrityError,API 兜底失效。 补上 CONSTRAINT uq_windup_project_user_name UNIQUE (user_id, project_name)。
…imiting - 注册/登录(邮箱+验证码+密码)、免密登录、刷新 token、登出、改密 - JWT 鉴权中间件(白名单放行 + request.state.current_user 注入) - 邮箱验证码(Redis 存储 + 冷却计时) - 接口限流中间件(Redis 滑动窗口 + 降级策略) - Redis 连接配置与客户端单例 - 22 个集成测试覆盖完整认证链路
- Add auth_client fixture with valid JWT token - Update test_project_api.py to use auth_client - Fix CI failures caused by auth middleware blocking unauthenticated requests
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
Three concrete regressions stood out: app startup now imports routers that are not present in the tree, the rate-limit middleware trusts a client-supplied forwarded-for header, and the compose defaults give Postgres and the backend different passwords.
|
|
||
| from windup_app.server.orchestrator.executor import run_action_task, run_image_task | ||
| from windup_app.web.api.auth import router as auth_router | ||
| from windup_app.web.api.character import router as character_router |
There was a problem hiding this comment.
High: both windup_app.web.api.character and windup_app.web.api.project are imported here, but neither module exists in this PR or the checked-out tree. create_app() will raise ModuleNotFoundError on startup before the server can accept requests.
|
|
||
| def _get_client_ip(request: Request) -> str: | ||
| """获取客户端 IP(优先 X-Forwarded-For)。""" | ||
| forwarded = request.headers.get("x-forwarded-for") |
There was a problem hiding this comment.
High: trusting X-Forwarded-For unconditionally lets any direct client spoof its source IP and sidestep the per-IP counters. Only honor this header behind a trusted proxy chain, or fall back to request.client.host.
| POSTGRES_HOST: postgres | ||
| POSTGRES_PORT: 5432 | ||
| POSTGRES_USER: ${POSTGRES_USER:-root} | ||
| POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-admin123} |
There was a problem hiding this comment.
High: this default password does not match the Postgres service above (W1ndup@2026!Secure at line 30). With no POSTGRES_PASSWORD set in the environment, the backend will try to connect with admin123 and fail on first boot.
概述
完整的用户认证体系:注册、登录、JWT 鉴权、邮箱验证码、接口限流。
包含内容
用户服务(server/user)
中间件(web/middleware)
AuthMiddleware:JWT 鉴权,白名单放行,注入request.state.current_userRateLimitMiddleware:Redis 滑动窗口限流,降级策略基础设施(framework)
测试
test_user_service.py:22 用例test_project_api.py:9 用例(含 auth_client fixture)关联