feat: 强化打包配置与服务安全

This commit is contained in:
shen
2026-07-18 13:30:56 +08:00
parent d1f070b251
commit a48909f3bc
26 changed files with 779 additions and 203 deletions
+29 -12
View File
@@ -1,15 +1,17 @@
"""FastAPI 主入口"""
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from .database import init_db
from .routers import config, apps, tasks, auth, users
from .services.log_streamer import log_streamer
from .config import BACKEND_PORT
from .config import BACKEND_PORT, CORS_ALLOWED_ORIGINS, TRUSTED_HOSTS, validate_production_security
from .deps import decode_current_user
STATIC_DIR = Path(__file__).parent / "static"
@@ -17,6 +19,7 @@ STATIC_DIR = Path(__file__).parent / "static"
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期"""
validate_production_security()
init_db()
yield
@@ -27,14 +30,17 @@ app = FastAPI(
lifespan=lifespan,
)
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 仅接受显式允许的跨域前端;同域部署不需要 CORS 配置。
if CORS_ALLOWED_ORIGINS:
app.add_middleware(
CORSMiddleware,
allow_origins=CORS_ALLOWED_ORIGINS,
allow_credentials=False,
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allow_headers=["Authorization", "Content-Type"],
)
app.add_middleware(TrustedHostMiddleware, allowed_hosts=TRUSTED_HOSTS)
# 路由
app.include_router(auth.router)
@@ -46,8 +52,19 @@ app.include_router(tasks.router)
@app.websocket("/ws/tasks/{task_id}")
async def websocket_logs(websocket: WebSocket, task_id: str):
"""WebSocket 实时日志"""
await websocket.accept()
"""经 JWT 鉴权的 WebSocket 实时日志"""
protocol = websocket.headers.get("sec-websocket-protocol", "")
token_protocol = next((item.strip() for item in protocol.split(",") if item.strip().startswith("jwt.")), "")
if not token_protocol:
await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
return
try:
decode_current_user(token_protocol.removeprefix("jwt."))
except Exception:
await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
return
await websocket.accept(subprotocol=token_protocol)
try:
async for msg in log_streamer.subscribe(task_id):
await websocket.send_json(msg)