| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- from __future__ import annotations
- from fastapi import APIRouter, HTTPException, Request, Response, status
- from api.schemas.auth import CreateAuthUserBody, LoginBody, UpdateAuthUserBody
- from api.services.auth import (
- SESSION_COOKIE_NAME,
- DuplicateUsernameError,
- InvalidCredentialsError,
- authenticate,
- create_user,
- delete_user,
- list_users,
- revoke_session,
- update_user,
- )
- from supply_infra.config import get_infra_settings
- router = APIRouter(prefix="/api", tags=["authentication"])
- @router.post("/auth/login")
- def login(body: LoginBody, request: Request, response: Response) -> dict:
- try:
- user, token = authenticate(
- username=body.username,
- password=body.password,
- ip_address=request.client.host if request.client else None,
- user_agent=request.headers.get("user-agent"),
- )
- except InvalidCredentialsError:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="用户名或密码错误",
- ) from None
- settings = get_infra_settings()
- response.set_cookie(
- key=SESSION_COOKIE_NAME,
- value=token,
- max_age=settings.auth_session_hours * 60 * 60,
- httponly=True,
- secure=settings.auth_cookie_secure,
- samesite="lax",
- path="/",
- )
- return {"user": user}
- @router.get("/auth/me")
- def me(request: Request) -> dict:
- return {"user": request.state.current_user}
- @router.post("/auth/logout")
- def logout(request: Request, response: Response) -> dict[str, bool]:
- token = request.cookies.get(SESSION_COOKIE_NAME)
- if token:
- revoke_session(token)
- response.delete_cookie(
- key=SESSION_COOKIE_NAME,
- path="/",
- secure=get_infra_settings().auth_cookie_secure,
- httponly=True,
- samesite="lax",
- )
- return {"ok": True}
- @router.get("/admin/users")
- def admin_users() -> dict:
- return {"items": list_users()}
- @router.post("/admin/users", status_code=201)
- def admin_create_user(body: CreateAuthUserBody) -> dict:
- try:
- return create_user(
- username=body.username,
- password=body.password,
- display_name=body.display_name,
- role=body.role,
- )
- except DuplicateUsernameError:
- raise HTTPException(status_code=409, detail="用户名已存在") from None
- @router.patch("/admin/users/{user_id}")
- def admin_update_user(
- user_id: int,
- body: UpdateAuthUserBody,
- request: Request,
- ) -> dict:
- current_user = request.state.current_user
- if current_user["id"] == user_id and (
- (body.role is not None and body.role != current_user["role"])
- or body.status == "disabled"
- or body.password is not None
- ):
- raise HTTPException(status_code=409, detail="不能降级、禁用或重置当前登录账号")
- result = update_user(
- user_id,
- display_name=body.display_name,
- role=body.role,
- status=body.status,
- password=body.password,
- )
- if result is None:
- raise HTTPException(status_code=404, detail="用户不存在")
- return result
- @router.delete("/admin/users/{user_id}", status_code=204)
- def admin_delete_user(user_id: int, request: Request) -> Response:
- if request.state.current_user["id"] == user_id:
- raise HTTPException(status_code=409, detail="不能删除当前登录账号")
- if not delete_user(user_id):
- raise HTTPException(status_code=404, detail="用户不存在")
- return Response(status_code=204)
|