from fastapi import Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from sqlalchemy.orm import Session from redis import Redis from app.core.db import get_db from app.core.security import decode_token from app.core.redis import get_redis from app.models import User from app.models.enums import StatusEnum bearer_scheme = HTTPBearer() def get_current_user( creds: HTTPAuthorizationCredentials = Depends(bearer_scheme), db: Session = Depends(get_db), redis: Redis = Depends(get_redis), ) -> User: token = creds.credentials try: payload = decode_token(token) except ValueError: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token") if payload.get("type") != "access": raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token") user_id = payload.get("sub") # Enforce redis-backed online session; if missing, force re-login online_key = f"auth:online:{user_id}" if not redis.exists(online_key): # Fallback: if refresh token exists for this user, recreate online key cursor = 0 found_ttl = None while True: cursor, keys = redis.scan(cursor=cursor, match="auth:refresh:*", count=200) for key in keys: try: val = redis.get(key) if val == str(user_id): ttl = redis.ttl(key) if ttl and ttl > 0: found_ttl = ttl break except Exception: continue if found_ttl is not None or cursor == 0: break if found_ttl is not None: redis.setex(online_key, found_ttl, "1") else: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Session expired") user = db.query(User).filter(User.user_id == int(user_id), User.is_deleted.is_(False)).first() if not user or user.status != int(StatusEnum.ENABLED): raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User disabled") return user