Files
hunjing/backend/app/auth/routes.py
T
2026-09-21 11:19:07 +08:00

73 lines
2.4 KiB
Python

"""认证路由:开发档登录/登出(Web Session Cookie)。
正式 OAuth 2.1 授权码流程(/oauth2/authorize、/oauth2/token、PKCE)属 WP-01
后续条目;本路由只建立 Session 边界骨架供垂直切片验证。
"""
from fastapi import APIRouter, HTTPException, Request, Response, status
from app.core.config import get_settings
from app.auth.service import (
SESSION_COOKIE,
create_session,
revoke_session,
)
from app.db.session import DbSession
from app.models import PersonalDomain, User
router = APIRouter(prefix="/v1/auth", tags=["auth"])
settings = get_settings()
@router.post("/sessions", status_code=201)
async def dev_login(
request: Request, response: Response, db: DbSession, body: dict[str, str]
) -> dict[str, str]:
"""开发档登录:按 email 找到或创建用户与个人域,签发会话。"""
email = body.get("email", "").strip().lower()
if not email or "@" not in email:
raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, "email 不合法")
from sqlalchemy import select
existing = (
(await db.execute(select(User).where(User.email == email))).scalar_one_or_none()
)
if existing is None:
admin_emails = {e.strip().lower() for e in settings.dev_admin_emails.split(",") if e.strip()}
user = User(
email=email,
display_name=email.split("@")[0],
role="admin" if email in admin_emails else "user",
)
db.add(user)
await db.flush()
domain = PersonalDomain(user_id=user.id, name="默认镜域")
db.add(domain)
await db.flush()
from app.characters.seeds import seed_default_character
await seed_default_character(db, domain.id)
else:
user = existing
_, token, csrf = await create_session(db, user.id)
await db.commit()
response.set_cookie(
SESSION_COOKIE,
token,
httponly=True,
secure=True,
samesite="lax",
path="/",
)
return {"csrf_token": csrf, "user_id": user.id, "role": user.role, "email": user.email}
@router.delete("/sessions/current", status_code=204)
async def logout(request: Request, response: Response, db: DbSession) -> None:
token = request.cookies.get(SESSION_COOKIE)
if token is not None and await revoke_session(db, token):
await db.commit()
response.delete_cookie(SESSION_COOKIE, path="/")