captcha_service.py 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. import uuid
  2. import base64
  3. import io
  4. from captcha.image import ImageCaptcha
  5. from app.core.cache import redis_client
  6. from app.core.config import settings
  7. class CaptchaService:
  8. @staticmethod
  9. def generate_captcha() -> dict:
  10. """
  11. Generates a captcha image, stores the code in Redis, and returns ID + B64 Image.
  12. """
  13. image = ImageCaptcha(width=280, height=90)
  14. # Generate 4 character code
  15. import random
  16. import string
  17. code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
  18. data = image.generate(code)
  19. # Create a unique ID
  20. captcha_id = str(uuid.uuid4())
  21. # Store in Redis: CAPTCHA:{uuid} -> code
  22. key = f"CAPTCHA:{captcha_id}"
  23. redis_client.setex(key, settings.CAPTCHA_EXPIRE_SECONDS, code)
  24. # Encode image to base64
  25. base64_image = base64.b64encode(data.getvalue()).decode('utf-8')
  26. return {
  27. "captcha_id": captcha_id,
  28. "image": f"data:image/png;base64,{base64_image}",
  29. "expire_seconds": settings.CAPTCHA_EXPIRE_SECONDS
  30. }
  31. @staticmethod
  32. def verify_captcha(captcha_id: str, code: str) -> bool:
  33. """
  34. Verifies the captcha code. Deletes the key after check (one-time use).
  35. """
  36. if not captcha_id or not code:
  37. return False
  38. key = f"CAPTCHA:{captcha_id}"
  39. stored_code = redis_client.get(key)
  40. if not stored_code:
  41. return False
  42. # Delete immediately to prevent replay
  43. redis_client.delete(key)
  44. return stored_code.upper() == code.upper()