gateway/modules/auth.py
2025-04-16 21:42:26 +02:00

159 lines
No EOL
4.9 KiB
Python

from datetime import datetime, timedelta, timezone
from typing import Optional, Dict, Any, Tuple
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
import logging
from modules.gateway_interface import get_gateway_interface
from modules.utility import APP_CONFIG
# Get Config Data
SECRET_KEY = APP_CONFIG.get("APP_JWT_SECRET_SECRET")
ALGORITHM = APP_CONFIG.get("Auth_ALGORITHM")
ACCESS_TOKEN_EXPIRE_MINUTES = int(APP_CONFIG.get("APP_TOKEN_EXPIRY"))
# OAuth2 Setup
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
# Logger
logger = logging.getLogger(__name__)
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
"""
Erstellt ein JWT Access Token.
Args:
data: Zu kodierende Daten (meist Benutzer-ID oder Benutzername)
expires_delta: Gültigkeitsdauer des Tokens (optional)
Returns:
JWT Token als String
"""
to_encode = data.copy()
if expires_delta:
expire = datetime.now(timezone.utc) + expires_delta
else:
expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
async def get_current_user(token: str = Depends(oauth2_scheme)) -> Dict[str, Any]:
"""
Extrahiert und validiert den aktuellen Benutzer aus dem JWT Token.
Args:
token: JWT Token aus dem Authorization-Header
Returns:
Benutzerdaten
Raises:
HTTPException: Bei ungültigem Token oder Benutzer
"""
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Ungültige Authentifizierungsdaten",
headers={"WWW-Authenticate": "Bearer"},
)
try:
# Token dekodieren
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
# Benutzername aus dem Token extrahieren
username: str = payload.get("sub")
if username is None:
raise credentials_exception
# Mandanten-ID aus dem Token extrahieren (falls vorhanden)
mandate_id: int = payload.get("mandate_id", 1) # Standard: Root-Mandant
except JWTError:
logger.warning("Ungültiges JWT Token")
raise credentials_exception
# Gateway-Interface ohne Kontext initialisieren
gateway = get_gateway_interface()
# Benutzer aus der Datenbank abrufen
user = gateway.get_user_by_username(username)
if user is None:
logger.warning(f"Benutzer {username} nicht gefunden")
raise credentials_exception
if user.get("disabled", False):
logger.warning(f"Benutzer {username} ist deaktiviert")
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Benutzer ist deaktiviert")
return user
async def get_current_active_user(current_user: Dict[str, Any] = Depends(get_current_user)) -> Dict[str, Any]:
"""
Stellt sicher, dass der Benutzer aktiv ist.
Args:
current_user: Aktuelle Benutzerdaten
Returns:
Benutzerdaten
Raises:
HTTPException: Wenn der Benutzer deaktiviert ist
"""
if current_user.get("disabled", False):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Benutzer ist deaktiviert")
return current_user
async def get_user_context(current_user: Dict[str, Any]) -> Tuple[int, int]:
"""
Extrahiert die Mandanten-ID und Benutzer-ID aus dem aktuellen Benutzer.
Enhanced with better logging.
Args:
current_user: Der aktuelle Benutzer
Returns:
Tuple von (mandate_id, user_id)
"""
# Default values
default_mandate_id = 0
default_user_id = 0
# Extract mandate_id
mandate_id = current_user.get("mandate_id", None)
if mandate_id is None:
logger.warning(f"No mandate_id found in current_user, using default: {default_mandate_id}")
mandate_id = default_mandate_id
else:
try:
mandate_id = int(mandate_id)
except (ValueError, TypeError):
logger.error(f"Invalid mandate_id value: {mandate_id}, using default: {default_mandate_id}")
mandate_id = default_mandate_id
# Extract user_id
user_id = current_user.get("id", None)
if user_id is None:
logger.warning(f"No user_id found in current_user, using default: {default_user_id}")
user_id = default_user_id
else:
try:
user_id = int(user_id)
except (ValueError, TypeError):
logger.error(f"Invalid user_id value: {user_id}, using default: {default_user_id}")
user_id = default_user_id
# logger.info(f"User context: mandate_id={mandate_id}, user_id={user_id}")
return mandate_id, user_id