dependencies.py
1 """ 2 FastAPI dependencies - reusable dependency injection functions. 3 """ 4 from fastapi import Depends, HTTPException, status, Cookie 5 from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials 6 from sqlalchemy.ext.asyncio import AsyncSession 7 from sqlalchemy import select 8 9 from database import get_db 10 from utils.auth import verify_access_token 11 from models.user import User 12 13 # HTTP Bearer token scheme (for Authorization header) 14 security = HTTPBearer(auto_error=False) 15 16 17 async def get_current_user( 18 db: AsyncSession = Depends(get_db), 19 credentials: HTTPAuthorizationCredentials | None = Depends(security), 20 token: str | None = Cookie(default=None) 21 ) -> User: 22 """ 23 Dependency to get the current authenticated user. 24 25 Checks for JWT token in: 26 1. Authorization header (Bearer token) 27 2. Cookie (http-only cookie named "token") 28 29 Usage in routes: 30 @router.get("/protected") 31 async def protected_route(current_user: User = Depends(get_current_user)): 32 # current_user is the authenticated User object 33 34 Raises: 35 HTTPException: 401 if not authenticated 36 """ 37 # TODO: Implement authentication check 38 # 39 # 1. Get token from either credentials.credentials (header) or token (cookie) 40 # 2. If no token found, raise 401 41 # 3. Verify token using verify_access_token() 42 # 4. If invalid, raise 401 43 # 5. Query database for user with that ID 44 # 6. If user not found or not active, raise 401 45 # 7. Return user object 46 # 47 # Example: 48 # token_str = None 49 # if credentials: 50 # token_str = credentials.credentials 51 # elif token: 52 # token_str = token 53 # 54 # if not token_str: 55 # raise HTTPException(status_code=401, detail="Not authenticated") 56 # 57 # user_id = verify_access_token(token_str) 58 # if not user_id: 59 # raise HTTPException(status_code=401, detail="Invalid token") 60 # 61 # result = await db.execute(select(User).where(User.id == user_id)) 62 # user = result.scalar_one_or_none() 63 # 64 # if not user or not user.active: 65 # raise HTTPException(status_code=401, detail="User not found") 66 # 67 # return user 68 69 raise HTTPException( 70 status_code=status.HTTP_401_UNAUTHORIZED, 71 detail="Not authenticated" 72 ) 73 74 75 async def get_optional_user( 76 db: AsyncSession = Depends(get_db), 77 credentials: HTTPAuthorizationCredentials | None = Depends(security), 78 token: str | None = Cookie(default=None) 79 ) -> User | None: 80 """ 81 Optional authentication - returns user if authenticated, None otherwise. 82 Does not raise an exception if not authenticated. 83 84 Useful for routes that behave differently for authenticated vs anonymous users. 85 """ 86 # TODO: Similar to get_current_user but returns None instead of raising exception 87 88 return None 89