from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import HTMLResponse, FileResponse from fastapi.exceptions import RequestValidationError from contextlib import asynccontextmanager from apps.urls import api_router from apps.settings.urls import UPLOAD_DIR from database import engine, get_db from models import Base from init_data import init_all_data from pathlib import Path from starlette.requests import Request from starlette.responses import JSONResponse @asynccontextmanager async def lifespan(app: FastAPI): # 启动时初始化数据库 async with engine.begin() as conn: # 创建所有表 await conn.run_sync(Base.metadata.create_all) # 初始化数据 async for db in get_db(): await init_all_data(db) break yield # 关闭时的清理工作 await engine.dispose() # 实例化FastAPI app = FastAPI( title="图书系统授权服务API", description="""图书系统授权服务API是一套用于用户认证和授权的服务,提供用户注册、登录、权限校验等功能。 同时实现了基于角色的访问控制(RBAC),支持自定义角色和权限。还增加了日志记录功能,方便监控和调试。""", version="1.0.0", lifespan=lifespan, docs_url=None, redoc_url="/redoc", ) # 开发环境前后端分离时的跨域(生产环境请收窄 allow_origins) app.add_middleware( CORSMiddleware, allow_origins=[ "http://localhost:5173", "http://127.0.0.1:5173", "http://localhost:3000", "http://127.0.0.1:3000", ], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], expose_headers=["X-Captcha-ID"], ) # 挂载swagger-ui静态文件目录 swagger_ui_path = Path(__file__).parent.parent / "swagger-ui" app.mount("/static", StaticFiles(directory=str(swagger_ui_path)), name="static") # 上传图片通过自定义端点提供(和 settings/urls.py 中的 UPLOAD_DIR 保持一致) @app.get("/uploads/{filename}") async def serve_upload(filename: str): """提供上传的图片文件""" file_path = UPLOAD_DIR / filename if not file_path.exists(): raise HTTPException(status_code=404, detail="文件不存在") return FileResponse(str(file_path)) # 自定义Swagger UI页面 @app.get("/docs", include_in_schema=False) async def custom_swagger_ui_html(): html_content = """