forked from xiaohei/taiji-AI-PAD
77 lines
2.7 KiB
Python
77 lines
2.7 KiB
Python
"""FastAPI application factory for the MCP server."""
|
|
|
|
from fastapi import FastAPI, Request
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.responses import JSONResponse
|
|
|
|
from .logging_config import configure_logging
|
|
from .metrics import register_http_metrics
|
|
from .lifecycle import register_lifecycle_events
|
|
from .routes import register_routes
|
|
from .state import get_state
|
|
from .auth import authenticate_request
|
|
from .rate_limiter import RateLimitMiddleware
|
|
from database import AsyncSessionLocal
|
|
|
|
|
|
def create_app() -> FastAPI:
|
|
"""Create and configure the FastAPI application."""
|
|
configure_logging()
|
|
settings = get_state().settings
|
|
|
|
app = FastAPI(
|
|
title="taiji-AI-PAD MCP Server",
|
|
description="Model Context Protocol Server for Agent Management",
|
|
version="1.0.0",
|
|
docs_url="/docs",
|
|
redoc_url="/redoc",
|
|
)
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=settings.cors_origins or ["*"],
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# 添加限流中间件(在认证中间件之前,以便能访问 principal)
|
|
app.add_middleware(RateLimitMiddleware)
|
|
|
|
register_http_metrics(app)
|
|
register_lifecycle_events(app)
|
|
register_routes(app)
|
|
|
|
@app.middleware("http")
|
|
async def auth_middleware(request: Request, call_next):
|
|
"""Enforce API Key/JWT on /api routes except login/health/metrics."""
|
|
# 跳过不需要认证的路径
|
|
skip_paths = ["/health", "/metrics", "/docs", "/redoc", "/openapi.json"]
|
|
if any(request.url.path.startswith(p) for p in skip_paths):
|
|
return await call_next(request)
|
|
|
|
# 认证逻辑:在独立的数据库会话中完成,不要包裹 call_next
|
|
principal = None
|
|
try:
|
|
async with AsyncSessionLocal() as session:
|
|
principal = await authenticate_request(request, session)
|
|
except Exception as e:
|
|
import logging
|
|
logging.getLogger(__name__).error(f"Auth middleware error during authentication: {e}")
|
|
principal = None
|
|
|
|
# 设置 principal 到 request.state
|
|
if principal:
|
|
request.state.principal = principal
|
|
elif request.url.path.startswith("/api") or request.url.path.startswith("/agents"):
|
|
# Allow unauthenticated access for checklist placeholder APIs while keeping
|
|
# any provided principal for future auth-enabled endpoints.
|
|
request.state.principal = {}
|
|
else:
|
|
request.state.principal = {}
|
|
|
|
# call_next 在数据库会话关闭后调用,避免长时间持有连接
|
|
return await call_next(request)
|
|
|
|
return app
|