80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.database import get_db
|
|
from app.models import User
|
|
from app.schemas import LoginRequest, SetupPasswordRequest, StatusResponse, TokenResponse
|
|
from app.services.auth import (
|
|
create_access_token,
|
|
decode_token,
|
|
get_or_create_profile,
|
|
get_user,
|
|
has_password,
|
|
hash_password,
|
|
verify_password,
|
|
)
|
|
|
|
router = APIRouter(prefix="/api/auth", tags=["auth"])
|
|
security = HTTPBearer(auto_error=False)
|
|
|
|
|
|
def require_auth(
|
|
creds: Optional[HTTPAuthorizationCredentials] = Depends(security),
|
|
db: Session = Depends(get_db),
|
|
) -> User:
|
|
if not creds:
|
|
raise HTTPException(401, "Требуется авторизация")
|
|
sub = decode_token(creds.credentials)
|
|
if not sub:
|
|
raise HTTPException(401, "Недействительный токен")
|
|
user = get_user(db)
|
|
if not user:
|
|
raise HTTPException(401, "Пользователь не найден")
|
|
return user
|
|
|
|
|
|
@router.get("/status", response_model=StatusResponse)
|
|
def auth_status(db: Session = Depends(get_db)) -> StatusResponse:
|
|
profile = get_or_create_profile(db)
|
|
return StatusResponse(
|
|
has_password=has_password(db),
|
|
onboarded=profile.onboarded,
|
|
phase=profile.phase,
|
|
)
|
|
|
|
|
|
@router.post("/setup", response_model=TokenResponse)
|
|
def setup_password(body: SetupPasswordRequest, db: Session = Depends(get_db)) -> TokenResponse:
|
|
if has_password(db):
|
|
raise HTTPException(400, "Пароль уже задан")
|
|
user = User(password_hash=hash_password(body.password), created_at=datetime.utcnow())
|
|
db.add(user)
|
|
get_or_create_profile(db)
|
|
db.commit()
|
|
profile = get_or_create_profile(db)
|
|
return TokenResponse(
|
|
access_token=create_access_token(),
|
|
needs_setup=False,
|
|
onboarded=profile.onboarded,
|
|
)
|
|
|
|
|
|
@router.post("/login", response_model=TokenResponse)
|
|
def login(body: LoginRequest, db: Session = Depends(get_db)) -> TokenResponse:
|
|
user = get_user(db)
|
|
if not user:
|
|
raise HTTPException(400, "Сначала задайте пароль")
|
|
if not verify_password(body.password, user.password_hash):
|
|
raise HTTPException(401, "Неверный пароль")
|
|
profile = get_or_create_profile(db)
|
|
return TokenResponse(
|
|
access_token=create_access_token(),
|
|
onboarded=profile.onboarded,
|
|
)
|