Files
giglez/src/api/dependencies.py
T

186 lines
4.7 KiB
Python

"""
FastAPI Dependencies
Shared dependencies for API endpoints
"""
from typing import Generator, Optional
from fastapi import Depends, HTTPException, status, Security
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session
from config.database import get_db_session
from config.settings import settings
from src.database.models import User
# =============================================================================
# DATABASE DEPENDENCY
# =============================================================================
def get_db() -> Generator[Session, None, None]:
"""
Database session dependency
Yields database session and ensures it's closed after request
"""
session = get_db_session()
try:
yield session
finally:
session.close()
# =============================================================================
# AUTHENTICATION DEPENDENCIES
# =============================================================================
# HTTP Bearer token scheme
security = HTTPBearer(auto_error=False)
def get_current_user(
credentials: Optional[HTTPAuthorizationCredentials] = Security(security),
db: Session = Depends(get_db)
) -> Optional[User]:
"""
Get current authenticated user from JWT token
Args:
credentials: Bearer token from Authorization header
db: Database session
Returns:
User object if authenticated, None if auth not required
Raises:
HTTPException: If authentication required but invalid
"""
# If authentication not required (development mode)
if not settings.require_auth:
# Return anonymous user (ID 0)
return db.query(User).filter_by(id=0).first()
# Authentication required
if not credentials:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Authentication required",
headers={"WWW-Authenticate": "Bearer"},
)
try:
# Decode JWT token (implementation in auth.py)
from src.api.auth import decode_access_token
payload = decode_access_token(credentials.credentials)
user_id = payload.get("sub")
if user_id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication token"
)
# Get user from database
user = db.query(User).filter_by(id=int(user_id)).first()
if user is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User not found"
)
return user
except Exception as e:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=f"Authentication failed: {str(e)}"
)
def require_auth(user: User = Depends(get_current_user)) -> User:
"""
Require authentication (always)
Use this dependency when endpoint must have authentication
regardless of global settings
Args:
user: Current user from get_current_user
Returns:
Authenticated user
Raises:
HTTPException: If user not authenticated
"""
if user is None or user.id == 0:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Authentication required for this endpoint"
)
return user
def optional_auth(user: Optional[User] = Depends(get_current_user)) -> Optional[User]:
"""
Optional authentication
Returns user if authenticated, None otherwise (no error)
Args:
user: Current user from get_current_user
Returns:
User if authenticated, None otherwise
"""
return user
# =============================================================================
# PAGINATION DEPENDENCIES
# =============================================================================
def get_pagination(
skip: int = 0,
limit: int = 100
) -> dict:
"""
Pagination parameters
Args:
skip: Number of records to skip
limit: Maximum number of records to return
Returns:
Dictionary with skip and limit
"""
# Enforce maximum limit
max_limit = 1000
if limit > max_limit:
limit = max_limit
return {
"skip": skip,
"limit": limit
}
# =============================================================================
# STORAGE DEPENDENCY
# =============================================================================
def get_storage():
"""
Get storage backend
Returns:
Storage backend instance (LocalStorage or S3Storage)
"""
from src.core.storage import get_storage
return get_storage()