This commit is contained in:
Iliyan Angelov
2025-12-04 01:07:34 +02:00
parent 5fb50983a9
commit 3d634b4fce
92 changed files with 9678 additions and 221 deletions

View File

@@ -1,7 +1,7 @@
from fastapi import Depends, HTTPException, status, Request, Cookie
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from jose import JWTError, jwt
from sqlalchemy.orm import Session
from sqlalchemy.orm import Session, joinedload
from typing import Optional
from datetime import datetime
import os
@@ -103,7 +103,8 @@ def get_current_user(
except ValueError as e:
# JWT secret configuration error - should not happen in production
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='Server configuration error')
user = db.query(User).filter(User.id == user_id).first()
# PERFORMANCE: Eager load role relationship to avoid N+1 queries in authorize_roles
user = db.query(User).options(joinedload(User.role)).filter(User.id == user_id).first()
if user is None:
raise credentials_exception
@@ -127,10 +128,17 @@ def get_current_user(
def authorize_roles(*allowed_roles: str):
def role_checker(current_user: User=Depends(get_current_user), db: Session=Depends(get_db)) -> User:
role = db.query(Role).filter(Role.id == current_user.role_id).first()
if not role:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='User role not found')
user_role_name = role.name
# PERFORMANCE: Use eager-loaded relationship if available, otherwise query
# This reduces database queries since get_current_user now eager loads the role
if hasattr(current_user, 'role') and current_user.role is not None:
user_role_name = current_user.role.name
else:
# Fallback: query role if relationship wasn't loaded (shouldn't happen, but safe)
role = db.query(Role).filter(Role.id == current_user.role_id).first()
if not role:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='User role not found')
user_role_name = role.name
if user_role_name not in allowed_roles:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='You do not have permission to access this resource')
return current_user
@@ -168,7 +176,8 @@ def get_current_user_optional(
except (JWTError, ValueError):
return None
user = db.query(User).filter(User.id == user_id).first()
# PERFORMANCE: Eager load role relationship for consistency
user = db.query(User).options(joinedload(User.role)).filter(User.id == user_id).first()
if user is None:
return None