feat: 强化打包配置与服务安全
This commit is contained in:
+29
-12
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user