auth.py 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. from datetime import datetime, timedelta, timezone
  2. from typing import Optional
  3. import bcrypt
  4. import jwt
  5. from fastapi import Depends, HTTPException, status
  6. from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
  7. from sqlalchemy import select
  8. from sqlalchemy.ext.asyncio import AsyncSession
  9. from .config import get_settings
  10. from .database import get_db
  11. from .models import Admin
  12. security = HTTPBearer()
  13. def hash_password(password: str) -> str:
  14. return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
  15. def verify_password(password: str, hashed: str) -> bool:
  16. return bcrypt.checkpw(password.encode(), hashed.encode())
  17. def create_token(admin_id: int, username: str) -> str:
  18. settings = get_settings()
  19. expire = datetime.now(timezone.utc) + timedelta(hours=settings.jwt_expire_hours)
  20. payload = {"sub": str(admin_id), "username": username, "exp": expire}
  21. return jwt.encode(payload, settings.jwt_secret, algorithm=settings.jwt_algorithm)
  22. def decode_token(token: str) -> Optional[dict]:
  23. settings = get_settings()
  24. try:
  25. return jwt.decode(token, settings.jwt_secret, algorithms=[settings.jwt_algorithm])
  26. except jwt.PyJWTError:
  27. return None
  28. async def get_current_admin(
  29. credentials: HTTPAuthorizationCredentials = Depends(security),
  30. db: AsyncSession = Depends(get_db),
  31. ) -> Admin:
  32. payload = decode_token(credentials.credentials)
  33. if not payload:
  34. raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
  35. admin_id = int(payload.get("sub", 0))
  36. result = await db.execute(select(Admin).where(Admin.id == admin_id, Admin.is_active == True))
  37. admin = result.scalar_one_or_none()
  38. if not admin:
  39. raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Admin not found")
  40. return admin