feat: add cookie sessions and backend role authorization

This commit is contained in:
2026-10-16 07:51:59 +08:00
parent 411eadb431
commit 3f25ffab83
28 changed files with 1186 additions and 31 deletions
+27 -3
View File
@@ -1,15 +1,17 @@
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from sqlalchemy import text
from sqlalchemy.exc import IntegrityError, OperationalError, ProgrammingError
from sqlalchemy.orm.exc import StaleDataError
from app.api.routes import chat, documents, health, knowledge, retrieval, sources
from app.api.routes import auth, chat, documents, health, knowledge, retrieval, sources
from app.core.config import settings
from app.db.session import engine
from app.services.auth import dummy_hash
from app.services.retrieval import tokenizer
@@ -19,7 +21,7 @@ def create_app(db_engine=engine) -> FastAPI:
try:
with db_engine.connect() as connection:
revision = connection.scalar(text("SELECT version_num FROM alembic_version"))
if revision != "0003_retrieval_runs":
if revision != "0004_auth_sessions":
raise RuntimeError(
"数据库版本不匹配,请先在 backend 目录执行 alembic upgrade head"
)
@@ -28,12 +30,13 @@ def create_app(db_engine=engine) -> FastAPI:
"数据库尚未初始化,请先在 backend 目录执行 alembic upgrade head"
) from exc
tokenizer()
dummy_hash()
try:
yield
finally:
db_engine.dispose()
app = FastAPI(title=settings.app_name, version="0.3.0", lifespan=lifespan)
app = FastAPI(title=settings.app_name, version="0.4.0", lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origin_list,
@@ -43,6 +46,7 @@ def create_app(db_engine=engine) -> FastAPI:
)
for router in (
health.router,
auth.router,
chat.router,
knowledge.router,
sources.router,
@@ -51,6 +55,26 @@ def create_app(db_engine=engine) -> FastAPI:
):
app.include_router(router, prefix=settings.api_prefix)
@app.middleware("http")
async def no_cache_api(request, call_next):
response = await call_next(request)
if request.url.path.startswith(settings.api_prefix + "/"):
response.headers["Cache-Control"] = "no-store"
return response
@app.exception_handler(RequestValidationError)
async def validation_handler(request, exc):
# FastAPI's default includes raw input (including passwords) in error responses.
return JSONResponse(
status_code=422,
content={
"detail": [
{"loc": list(error["loc"]), "msg": error["msg"], "type": error["type"]}
for error in exc.errors()
]
},
)
@app.exception_handler(StaleDataError)
async def stale_data_handler(request, exc):
return JSONResponse(status_code=409, content={"detail": "记录已更新,请刷新后重试"})