← full-stack-fastapi-template  /  backend/app/api/deps.py

1
from collections.abc import Generator
2
from typing import Annotated
3
4
import jwt
5
from fastapi import Depends, HTTPException, status
6
from fastapi.security import OAuth2PasswordBearer
7
from jwt.exceptions import InvalidTokenError
8
from pydantic import ValidationError
9
from sqlmodel import Session
10
11
from app.core import security
12
from app.core.config import settings
13
from app.core.db import engine
14
from app.models import TokenPayload, User
15
16
reusable_oauth2 = OAuth2PasswordBearer(
17
    tokenUrl=f"{settings.API_V1_STR}/login/access-token"
18
)
19
20
21
def get_db() -> Generator[Session, None, None]:
22
    with Session(engine) as session:
23
        yield session
24
25
26
SessionDep = Annotated[Session, Depends(get_db)]
27
TokenDep = Annotated[str, Depends(reusable_oauth2)]
28
29
30
def get_current_user(session: SessionDep, token: TokenDep) -> User:
31
    try:
32
        payload = jwt.decode(
33
            token, settings.SECRET_KEY, algorithms=[security.ALGORITHM]
34
        )
35
        token_data = TokenPayload(**payload)
36
    except (InvalidTokenError, ValidationError):
37
        raise HTTPException(
38
            status_code=status.HTTP_403_FORBIDDEN,
39
            detail="Could not validate credentials",
40
        )
41
    user = session.get(User, token_data.sub)
42
    if not user:
43
        raise HTTPException(status_code=404, detail="User not found")
44
    if not user.is_active:
45
        raise HTTPException(status_code=400, detail="Inactive user")
46
    return user
47
48
49
CurrentUser = Annotated[User, Depends(get_current_user)]
50
51
52
def get_current_active_superuser(current_user: CurrentUser) -> User:
53
    if not current_user.is_superuser:
54
        raise HTTPException(
55
            status_code=403, detail="The user doesn't have enough privileges"
56
        )
57
    return current_user
58