feat(api): роутеры API v1 и WebSocket-поток метрик (Refs #19)
- ops: health/ready/metrics без аутентификации (503 = схема Error). - auth: login/logout/session, cookie-сессия + CSRF-токен. - status/config/routing/devices+logs: все эндпоинты контракта. - ws/metrics: /api/v1/metrics/stream, токен в заголовке или query.
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
"""Аутентификация UI и API: /api/v1/auth/*."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Annotated, Any
|
||||
|
||||
from fastapi import APIRouter, Depends, Response
|
||||
|
||||
from awg_api.deps import SESSION_COOKIE_NAME, StateDep, require_token
|
||||
from awg_api.schemas import AuthLoginRequest
|
||||
|
||||
router = APIRouter(prefix="/api/v1/auth", tags=["auth"])
|
||||
TokenDep = Annotated[None, Depends(require_token)]
|
||||
|
||||
|
||||
@router.post("/login")
|
||||
async def login(payload: AuthLoginRequest, state: StateDep, response: Response) -> dict[str, Any]:
|
||||
session = state.login(payload.username, payload.password)
|
||||
csrf_token = session["csrf_token"]
|
||||
if isinstance(csrf_token, str):
|
||||
response.set_cookie(
|
||||
SESSION_COOKIE_NAME, csrf_token, httponly=True, samesite="strict", path="/"
|
||||
)
|
||||
return session
|
||||
|
||||
|
||||
@router.post("/logout")
|
||||
async def logout(state: StateDep, _: TokenDep = None) -> dict[str, Any]:
|
||||
return state.logout()
|
||||
|
||||
|
||||
@router.get("/session")
|
||||
async def get_session(state: StateDep, _: TokenDep = None) -> dict[str, Any]:
|
||||
return state.get_session()
|
||||
Reference in New Issue
Block a user