[FEAT] (사용자 로직) : 인증 서비스 구현 완료
v0.1.2 (2025-11-16) - 로그인, 로그아웃, 토큰 갱신, 회원가입 API 구현 완료 - 로그 포맷 통일화
This commit is contained in:
@@ -1,4 +1,168 @@
|
||||
"""
|
||||
캐시 서비스
|
||||
Redis 기반 캐싱 로직 관리하는 서비스 레이어
|
||||
"""
|
||||
"""
|
||||
|
||||
import json
|
||||
from typing import Optional, Dict, Any
|
||||
from extensions import redis_cli
|
||||
import settings
|
||||
|
||||
|
||||
from extensions import custom_logger
|
||||
|
||||
logger = custom_logger(f"{settings.LOG_PREFIX}_auth_service")
|
||||
class CacheService:
|
||||
|
||||
@staticmethod
|
||||
def _is_redis_available() -> bool:
|
||||
"""Redis 연결 상태 확인"""
|
||||
return redis_cli.is_connected()
|
||||
|
||||
@staticmethod
|
||||
def set(key: str, value: Any, ttl: int) -> bool:
|
||||
"""Redis에 데이터 저장"""
|
||||
if not CacheService._is_redis_available():
|
||||
logger.warning("레디스가 연결되어 있지 않습니다. 등록 로직을 ㄴ생략합니다.")
|
||||
return False
|
||||
|
||||
try:
|
||||
if isinstance(value, dict):
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
|
||||
redis_cli.redis_client.setex(key, ttl, value)
|
||||
logger.debug(f"캐시 저장: {key} (TTL: {ttl}s)")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"캐시 저장 실패: {key} - {str(e)}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def get(key: str, parse_json: bool = True) -> Optional[Any]:
|
||||
"""Redis에서 데이터 조회"""
|
||||
if not CacheService._is_redis_available():
|
||||
logger.warning("레디스가 연결되어 있지 않습니다. 조회 로직을 생략합니다.")
|
||||
return None
|
||||
|
||||
try:
|
||||
value = redis_cli.redis_client.get(key)
|
||||
|
||||
if value:
|
||||
logger.debug(f"Cache hit: {key}")
|
||||
if parse_json:
|
||||
return json.loads(value)
|
||||
return value
|
||||
|
||||
logger.debug(f"Cache miss: {key}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get cache {key}: {str(e)}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def delete(key: str) -> bool:
|
||||
"""Redis에서 데이터 삭제
|
||||
|
||||
Args:
|
||||
key: Redis 키
|
||||
|
||||
Returns:
|
||||
bool: 성공 여부
|
||||
"""
|
||||
if not CacheService._is_redis_available():
|
||||
logger.warning("레디스가 연결되어 있지 않습니다. 삭제가 불가능 합니다.")
|
||||
return False
|
||||
|
||||
try:
|
||||
redis_cli.redis_client.delete(key)
|
||||
logger.debug(f"Cache deleted: {key}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to delete cache {key}: {str(e)}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def exists(key: str) -> bool:
|
||||
"""Redis에 키가 존재하는지 확인"""
|
||||
if not CacheService._is_redis_available():
|
||||
logger.warning("레디스가 연결되어 있지 않습니다. 조회가 불가능 합니다.")
|
||||
return False
|
||||
|
||||
try:
|
||||
return redis_cli.redis_client.exists(key) > 0
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to check cache existence {key}: {str(e)}")
|
||||
return False
|
||||
|
||||
class UserCacheService:
|
||||
"""사용자 캐시 관리 서비스"""
|
||||
|
||||
PREFIX = "user:cache:"
|
||||
TTL = settings.REDIS_USER_CACHE_TTL
|
||||
|
||||
@classmethod
|
||||
def _get_key(cls, user_uuid: str) -> str:
|
||||
"""캐시 키 생성"""
|
||||
return f"{cls.PREFIX}{user_uuid}"
|
||||
|
||||
@classmethod
|
||||
def set(cls, user_uuid: str, user_data: Dict[str, Any], ttl: Optional[int] = None) -> bool:
|
||||
"""사용자 정보를 Redis에 캐싱"""
|
||||
key = cls._get_key(user_uuid)
|
||||
ttl = ttl or cls.TTL
|
||||
return CacheService.set(key, user_data, ttl)
|
||||
|
||||
@classmethod
|
||||
def get(cls, user_uuid: str) -> Optional[Dict[str, Any]]:
|
||||
"""Redis에서 사용자 정보 조회"""
|
||||
key = cls._get_key(user_uuid)
|
||||
return CacheService.get(key, parse_json=True)
|
||||
|
||||
@classmethod
|
||||
def delete(cls, user_uuid: str) -> bool:
|
||||
"""캐시에서 사용자 정보 삭제"""
|
||||
key = cls._get_key(user_uuid)
|
||||
return CacheService.delete(key)
|
||||
|
||||
@classmethod
|
||||
def refresh(cls, user_uuid: str, user_data: Dict[str, Any]) -> bool:
|
||||
"""캐시 갱신 (삭제 후 재설정)"""
|
||||
cls.delete(user_uuid)
|
||||
return cls.set(user_uuid, user_data)
|
||||
|
||||
|
||||
class JWTBlacklistService:
|
||||
"""JWT 블랙리스트 관리 서비스 (로그아웃된 토큰 추적)"""
|
||||
|
||||
PREFIX = "jwt:blacklist:"
|
||||
TTL = settings.REDIS_JWT_BLACKLIST_TTL
|
||||
|
||||
@classmethod
|
||||
def _get_key(cls, jti: str) -> str:
|
||||
"""블랙리스트 키 생성"""
|
||||
return f"{cls.PREFIX}{jti}"
|
||||
|
||||
@classmethod
|
||||
def add(cls, jti: str, ttl: Optional[int] = None) -> bool:
|
||||
"""블랙리스트에 토큰 추가"""
|
||||
key = cls._get_key(jti)
|
||||
ttl = ttl or cls.TTL
|
||||
|
||||
if not CacheService._is_redis_available():
|
||||
logger.warning("레디스가 연결되어 있지 않습니다. 블랙리스트에 추가가 블가능합니다.")
|
||||
return False
|
||||
|
||||
success = CacheService.set(key, "1", ttl)
|
||||
if success:
|
||||
logger.info(f"JWT 블랙리스트 추가완료: {jti}")
|
||||
return success
|
||||
|
||||
@classmethod
|
||||
def is_blacklisted(cls, jti: str) -> bool:
|
||||
"""토큰이 블랙리스트에 있는지 확인"""
|
||||
key = cls._get_key(jti)
|
||||
return CacheService.exists(key)
|
||||
Reference in New Issue
Block a user