133 lines
4.0 KiB
Python
133 lines
4.0 KiB
Python
from fastapi import FastAPI
|
||
from fastapi.middleware.cors import CORSMiddleware
|
||
from fastapi.staticfiles import StaticFiles
|
||
from fastapi.responses import HTMLResponse
|
||
from contextlib import asynccontextmanager
|
||
from apps.urls import api_router
|
||
from database import engine, get_db
|
||
from models import Base
|
||
from init_data import init_all_data
|
||
from pathlib import Path
|
||
|
||
|
||
@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")
|
||
|
||
|
||
# 自定义Swagger UI页面
|
||
@app.get("/docs", include_in_schema=False)
|
||
async def custom_swagger_ui_html():
|
||
html_content = """
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Book System API - Swagger UI</title>
|
||
<link rel="stylesheet" type="text/css" href="/static/swagger-ui.css">
|
||
<link rel="icon" type="image/png" href="/static/favicon-32x32.png" sizes="32x32"/>
|
||
<style>
|
||
html {
|
||
box-sizing: border-box;
|
||
overflow: -moz-scrollbars-vertical;
|
||
overflow-y: scroll;
|
||
}
|
||
*, *:before, *:after {
|
||
box-sizing: inherit;
|
||
}
|
||
body {
|
||
margin: 0;
|
||
background: #fafafa;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="swagger-ui"></div>
|
||
<script src="/static/swagger-ui-bundle.js"></script>
|
||
<script>
|
||
window.onload = function() {
|
||
const ui = SwaggerUIBundle({
|
||
url: "/openapi.json",
|
||
dom_id: '#swagger-ui',
|
||
deepLinking: true,
|
||
presets: [
|
||
SwaggerUIBundle.presets.apis,
|
||
SwaggerUIBundle.SwaggerUIStandalonePreset
|
||
],
|
||
layout: "BaseLayout",
|
||
persistAuthorization: true,
|
||
docExpansion: "list"
|
||
});
|
||
window.ui = ui;
|
||
};
|
||
</script>
|
||
</body>
|
||
</html>
|
||
"""
|
||
return HTMLResponse(content=html_content)
|
||
|
||
|
||
# 包含路由
|
||
app.include_router(api_router)
|
||
|
||
|
||
# 声明装饰器方法和路径
|
||
@app.get("/")
|
||
# 声明装饰器函数
|
||
async def home():
|
||
return {"message": "Hello World!!!"}
|
||
|
||
|
||
# 如果使用命令行启动,使用uvicorn 文件名:app --reload启动即可,下面命令就不用写
|
||
# 如果写下面的命令,就不需要命令行启动了,直接用IDE运行即可
|
||
if __name__ == "__main__":
|
||
import uvicorn
|
||
import os
|
||
|
||
name = f"{os.path.splitext(os.path.basename(os.path.abspath(__file__)))[0]}:app"
|
||
uvicorn.run(name, host="0.0.0.0", port=8000, reload=True, reload_dirs=["_"])
|