-
Notifications
You must be signed in to change notification settings - Fork 4
feat(user): 用户认证模块——注册/登录/JWT/验证码/限流 #149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
xiaocheny214
wants to merge
6
commits into
1024XEngineer:main
Choose a base branch
from
xiaocheny214:feat/user-auth
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
c042937
feat(docker): add Docker Compose deployment for backend and PostgreSQL
xiaocheny214 dc3c362
fix(deploy): make the container build and the API reachable from the …
Soli22de 0fb5bf0
fix(deps): docker-compose 添加 Redis 服务,注入 REDIS_URL
xiaocheny214 f99f30b
fix(db): init.sql 补充 windup_project 唯一约束,对齐 ORM 声明
xiaocheny214 13dae21
feat(user): add user module with JWT auth, email verification, rate l…
xiaocheny214 401cd92
fix(test): add auth_client fixture for project API tests
xiaocheny214 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # ── 后端 Dockerfile ────────────────────────────────────────────────── | ||
| # 多阶段构建:builder 装依赖 → runtime 只拷贝产物,镜像更小 | ||
|
|
||
| # ── 阶段 1: 构建 ── | ||
| FROM python:3.12-slim AS builder | ||
|
|
||
| # 安装 uv(比 pip 快 10x) | ||
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv | ||
|
|
||
| # ── 国内网络:走镜像源 + 拉长超时 ──────────────────────────────────────── | ||
| # 实测(2026-08-04,这台服务器):宿主机访问 pypi.org 需 8s,构建容器内默认超时 | ||
| # 会在下载大包(uvloop)时 "operation timed out" 直接失败。 | ||
| ENV UV_DEFAULT_INDEX=https://mirrors.aliyun.com/pypi/simple/ \ | ||
| UV_HTTP_TIMEOUT=180 | ||
|
|
||
| # 必须与 runtime 阶段同路径 —— venv 内的 shebang/.pth 是绝对路径,跨路径拷贝会失效 | ||
| WORKDIR /app | ||
|
|
||
| # 先拷贝依赖定义,利用 Docker layer cache | ||
| COPY pyproject.toml uv.lock ./ | ||
| COPY packages/common/pyproject.toml packages/common/ | ||
| COPY packages/framework/pyproject.toml packages/framework/ | ||
| COPY packages/ai_engine/pyproject.toml packages/ai_engine/ | ||
| COPY packages/app/pyproject.toml packages/app/ | ||
|
|
||
| # 安装依赖(不含 dev 依赖) | ||
| RUN uv sync --frozen --no-dev --no-install-workspace | ||
|
|
||
| # 拷贝源码并安装 | ||
| COPY packages/ packages/ | ||
| RUN uv sync --frozen --no-dev | ||
|
|
||
| # ── 阶段 2: 运行时 ── | ||
| FROM python:3.12-slim AS runtime | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| # 从 builder 拷贝虚拟环境和包 | ||
| COPY --from=builder /app/.venv /app/.venv | ||
| COPY --from=builder /app/packages /app/packages | ||
|
|
||
| # 把 venv/bin 加入 PATH | ||
| ENV PATH="/app/.venv/bin:$PATH" | ||
|
|
||
| # 默认环境变量(可被 docker-compose / .env 覆盖) | ||
| ENV WINDUP_HOST=0.0.0.0 | ||
| ENV WINDUP_PORT=8000 | ||
| ENV WINDUP_RELOAD=false | ||
|
|
||
| EXPOSE 8000 | ||
|
|
||
| # 健康检查 | ||
| HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ | ||
| CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/docs')" || exit 1 | ||
|
|
||
| # 启动命令 | ||
| CMD ["uvicorn", "windup_app.bootstrap.app:create_app", "--factory", "--host", "0.0.0.0", "--port", "8000"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,104 @@ | ||
|
|
||
| """FastAPI 应用工厂与装配入口。 | ||
|
|
||
| ``create_app`` 负责创建 FastAPI 实例并挂载路由 / 中间件 / 异常处理, | ||
| 是整个 web 服务的唯一装配点(composition root)。 | ||
|
|
||
| ``main`` 是开发启动入口:``python -m windup_app`` 或 ``windup`` 命令。 | ||
| """ | ||
|
|
||
| import os | ||
| from contextlib import asynccontextmanager | ||
|
|
||
| import windup_framework.db # noqa: F401 组装时显式触发 DB engine/session 初始化 | ||
| from fastapi import FastAPI | ||
| from fastapi.middleware.cors import CORSMiddleware | ||
|
|
||
| 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 | ||
| from windup_app.web.api.generation import router as generation_router | ||
| from windup_app.web.api.media import router as media_router | ||
| from windup_app.web.api.project import router as project_router | ||
| from windup_app.web.handler.exception_handlers import register_exception_handlers | ||
| from windup_app.web.middleware.auth import AuthMiddleware | ||
| from windup_app.web.middleware.ratelimit import RateLimitMiddleware | ||
|
|
||
|
|
||
| def _env_flag(name: str) -> bool: | ||
| """把环境变量解析为真正的布尔值:仅 1/true/yes/on(忽略大小写与空白)视为 True。""" | ||
| return os.getenv(name, "").strip().lower() in {"1", "true", "yes", "on"} | ||
|
|
||
|
|
||
|
|
||
| def _cors_origins() -> list[str]: | ||
| """允许跨域的前端来源,逗号分隔的 WINDUP_CORS_ORIGINS 覆盖。 | ||
|
|
||
| 不配这个中间件的话,浏览器会把前端的**所有**请求拦在预检那一步 | ||
| (OPTIONS 返回 405、响应无 access-control-* 头),后端日志里连请求都看不到。 | ||
| 默认值覆盖本地 dev server 与 Vercel 预览域名。 | ||
| """ | ||
| raw = os.getenv("WINDUP_CORS_ORIGINS", "").strip() | ||
| if raw: | ||
| return [o.strip() for o in raw.split(",") if o.strip()] | ||
| return ["http://localhost:5173", "http://127.0.0.1:5173", | ||
| "http://localhost:3000", "http://127.0.0.1:3000"] | ||
|
|
||
|
|
||
| def print_banner() -> None: | ||
| """启动时打印 banner(占位实现,后续替换为正式 ASCII banner)。""" | ||
| print("windup 0.1.0 starting ...") | ||
|
|
||
|
|
||
| @asynccontextmanager | ||
| async def _lifespan(app: FastAPI): | ||
| """应用启动时打印 banner,关闭时无特殊处理。""" | ||
| print_banner() | ||
| yield | ||
|
|
||
|
|
||
| def create_app() -> FastAPI: | ||
| app = FastAPI(title="windup", version="0.1.0") | ||
| app = FastAPI(title="windup", version="0.1.0", lifespan=_lifespan) | ||
|
|
||
| # 中间件(执行顺序:请求先进 RateLimit,再进 Auth,最后到路由) | ||
| app.add_middleware(RateLimitMiddleware) | ||
| app.add_middleware(AuthMiddleware) | ||
|
|
||
| # 路由 | ||
| app.include_router(auth_router) | ||
| app.add_middleware( | ||
| CORSMiddleware, | ||
| allow_origins=_cors_origins(), | ||
| allow_origin_regex=r"https://.*\.vercel\.app", | ||
| allow_credentials=True, | ||
| allow_methods=["*"], | ||
| allow_headers=["*"], | ||
| ) | ||
| app.include_router(project_router) | ||
| app.include_router(character_router) | ||
| app.include_router(media_router) | ||
| app.include_router(generation_router) | ||
|
|
||
| # 生成后台调度器注入 app.state | ||
| app.state.run_action_task = run_action_task | ||
| app.state.run_image_task = run_image_task | ||
|
|
||
| register_exception_handlers(app) | ||
| return app | ||
|
|
||
|
|
||
| def main() -> None: | ||
| """开发启动入口:用 uvicorn 跑 ``create_app``。""" | ||
| import uvicorn | ||
|
|
||
| uvicorn.run( | ||
| "windup_app.bootstrap.app:create_app", | ||
| factory=True, | ||
| host=os.getenv("WINDUP_HOST", "127.0.0.1"), | ||
| port=int(os.getenv("WINDUP_PORT", "8000")), | ||
| reload=_env_flag("WINDUP_RELOAD"), | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
High: both
windup_app.web.api.characterandwindup_app.web.api.projectare imported here, but neither module exists in this PR or the checked-out tree.create_app()will raiseModuleNotFoundErroron startup before the server can accept requests.