2025-07-31 18:55:59 +03:00
|
|
|
|
import datetime
|
|
|
|
|
import logging
|
|
|
|
|
from typing import Any, Dict, Optional
|
2023-10-30 22:00:55 +01:00
|
|
|
|
|
2023-10-26 22:38:31 +02:00
|
|
|
|
import jwt
|
2023-10-30 22:00:55 +01:00
|
|
|
|
|
2025-07-31 18:55:59 +03:00
|
|
|
|
from settings import JWT_ALGORITHM, JWT_ISSUER, JWT_REFRESH_TOKEN_EXPIRE_DAYS, JWT_SECRET_KEY
|
2023-10-26 22:38:31 +02:00
|
|
|
|
|
2021-06-28 12:08:09 +03:00
|
|
|
|
|
2022-07-21 14:58:50 +03:00
|
|
|
|
class JWTCodec:
|
2025-07-31 18:55:59 +03:00
|
|
|
|
"""
|
|
|
|
|
Кодировщик и декодировщик JWT токенов.
|
|
|
|
|
"""
|
|
|
|
|
|
2022-09-03 13:50:14 +03:00
|
|
|
|
@staticmethod
|
2025-07-31 18:55:59 +03:00
|
|
|
|
def encode(
|
|
|
|
|
payload: Dict[str, Any],
|
|
|
|
|
secret_key: Optional[str] = None,
|
|
|
|
|
algorithm: Optional[str] = None,
|
|
|
|
|
expiration: Optional[datetime.datetime] = None,
|
|
|
|
|
) -> str | bytes:
|
|
|
|
|
"""
|
|
|
|
|
Кодирует payload в JWT токен.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
payload (Dict[str, Any]): Полезная нагрузка для кодирования
|
|
|
|
|
secret_key (Optional[str]): Секретный ключ. По умолчанию используется JWT_SECRET_KEY
|
|
|
|
|
algorithm (Optional[str]): Алгоритм шифрования. По умолчанию используется JWT_ALGORITHM
|
|
|
|
|
expiration (Optional[datetime.datetime]): Время истечения токена
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
str: Закодированный JWT токен
|
|
|
|
|
"""
|
|
|
|
|
logger = logging.getLogger("root")
|
|
|
|
|
logger.debug(f"[JWTCodec.encode] Кодирование токена для payload: {payload}")
|
|
|
|
|
|
|
|
|
|
# Используем переданные или дефолтные значения
|
|
|
|
|
secret_key = secret_key or JWT_SECRET_KEY
|
|
|
|
|
algorithm = algorithm or JWT_ALGORITHM
|
|
|
|
|
|
|
|
|
|
# Если время истечения не указано, устанавливаем дефолтное
|
|
|
|
|
if not expiration:
|
|
|
|
|
expiration = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(
|
|
|
|
|
days=JWT_REFRESH_TOKEN_EXPIRE_DAYS
|
|
|
|
|
)
|
|
|
|
|
logger.debug(f"[JWTCodec.encode] Время истечения не указано, устанавливаем срок: {expiration}")
|
|
|
|
|
|
|
|
|
|
# Формируем payload с временными метками
|
|
|
|
|
payload.update(
|
|
|
|
|
{"exp": int(expiration.timestamp()), "iat": datetime.datetime.now(datetime.timezone.utc), "iss": JWT_ISSUER}
|
|
|
|
|
)
|
2025-05-29 12:37:39 +03:00
|
|
|
|
|
2025-05-20 00:00:24 +03:00
|
|
|
|
logger.debug(f"[JWTCodec.encode] Сформирован payload: {payload}")
|
2025-05-29 12:37:39 +03:00
|
|
|
|
|
2022-10-23 12:33:28 +03:00
|
|
|
|
try:
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Используем PyJWT для кодирования
|
|
|
|
|
encoded = jwt.encode(payload, secret_key, algorithm=algorithm)
|
|
|
|
|
token_str = encoded.decode("utf-8") if isinstance(encoded, bytes) else encoded
|
|
|
|
|
return token_str
|
2022-10-23 12:33:28 +03:00
|
|
|
|
except Exception as e:
|
2025-07-31 18:55:59 +03:00
|
|
|
|
logger.warning(f"[JWTCodec.encode] Ошибка при кодировании JWT: {e}")
|
2025-05-20 00:00:24 +03:00
|
|
|
|
raise
|
2021-06-28 12:08:09 +03:00
|
|
|
|
|
2022-09-03 13:50:14 +03:00
|
|
|
|
@staticmethod
|
2025-07-31 18:55:59 +03:00
|
|
|
|
def decode(
|
|
|
|
|
token: str,
|
|
|
|
|
secret_key: Optional[str] = None,
|
|
|
|
|
algorithms: Optional[list] = None,
|
|
|
|
|
) -> Dict[str, Any]:
|
|
|
|
|
"""
|
|
|
|
|
Декодирует JWT токен.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
token (str): JWT токен
|
|
|
|
|
secret_key (Optional[str]): Секретный ключ. По умолчанию используется JWT_SECRET_KEY
|
|
|
|
|
algorithms (Optional[list]): Список алгоритмов. По умолчанию используется [JWT_ALGORITHM]
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Dict[str, Any]: Декодированный payload
|
|
|
|
|
"""
|
|
|
|
|
logger = logging.getLogger("root")
|
|
|
|
|
logger.debug("[JWTCodec.decode] Декодирование токена")
|
|
|
|
|
|
|
|
|
|
# Используем переданные или дефолтные значения
|
|
|
|
|
secret_key = secret_key or JWT_SECRET_KEY
|
|
|
|
|
algorithms = algorithms or [JWT_ALGORITHM]
|
2025-05-29 12:37:39 +03:00
|
|
|
|
|
2022-10-23 12:33:28 +03:00
|
|
|
|
try:
|
2025-07-31 18:55:59 +03:00
|
|
|
|
# Используем PyJWT для декодирования
|
|
|
|
|
decoded = jwt.decode(token, secret_key, algorithms=algorithms)
|
|
|
|
|
return decoded
|
2022-11-01 00:05:10 +03:00
|
|
|
|
except jwt.ExpiredSignatureError:
|
2025-07-31 18:55:59 +03:00
|
|
|
|
logger.warning("[JWTCodec.decode] Токен просрочен")
|
|
|
|
|
raise
|
|
|
|
|
except jwt.InvalidTokenError as e:
|
|
|
|
|
logger.warning(f"[JWTCodec.decode] Ошибка при декодировании JWT: {e}")
|
|
|
|
|
raise
|