Что такое JWT и как его использовать?

Ответ

JWT (JSON Web Token) — это открытый стандарт (RFC 7519) для безопасной передачи информации между сторонами в виде объекта JSON. Информация может быть верифицирована и доверена, поскольку она подписана цифровой подписью.

Структура JWT: Токен состоит из трех частей, разделенных точками:

  1. Header (Заголовок): Содержит тип токена (JWT) и используемый алгоритм подписи (например, HS256, RS256).
  2. Payload (Нагрузка): Содержит утверждения (claims) — информацию о сущности (обычно пользователе) и дополнительные данные. Может включать стандартные поля (iss, exp, sub) и пользовательские.
  3. Signature (Подпись): Создается путем кодирования заголовка и нагрузки в Base64Url, объединения их точкой и подписи полученной строки с использованием секретного ключа и алгоритма из заголовка.

Сценарии использования:

  • Аутентификация: После входа пользователя сервер выдает JWT, который клиент затем отправляет с каждым запросом для доступа к защищенным маршрутам.
  • Авторизация: В Payload можно включить информацию о ролях и разрешениях пользователя.
  • Обмен информацией: Безопасный обмен данными между микросервисами или между клиентом и сервером.

Пример создания и верификации JWT в Python (PyJWT):

import jwt
from datetime import datetime, timedelta

# Секретный ключ для подписи токена. Должен храниться безопасно!
SECRET_KEY = "your-super-secret-key-that-no-one-knows"
ALGORITHM = "HS256"

# Создание токена
def create_jwt_token(user_id: int, expires_delta: timedelta = None) -> str:
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=30) # По умолчанию 30 минут

    payload = {
        "user_id": user_id,
        "exp": expire, # Время истечения токена
        "iat": datetime.utcnow() # Время выдачи токена
    }
    encoded_jwt = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

# Декодирование и проверка токена
def verify_jwt_token(token: str) -> dict | None:
    try:
        decoded_payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return decoded_payload
    except jwt.ExpiredSignatureError:
        print("Ошибка: Токен истек.")
        return None
    except jwt.InvalidTokenError:
        print("Ошибка: Невалидный токен.")
        return None

# Использование
token = create_jwt_token(user_id=123, expires_delta=timedelta(hours=1))
print(f"Созданный токен: {token}")

decoded_data = verify_jwt_token(token)
if decoded_data:
    print(f"Декодированные данные: {decoded_data}")

Важные аспекты и лучшие практики:

  • Безопасность ключа: Секретный ключ должен быть надежным и храниться в безопасном месте, не в коде.
  • HTTPS: Всегда передавайте JWT по защищенному соединению (HTTPS), чтобы предотвратить перехват.
  • Время жизни токена (exp): Устанавливайте разумное время истечения токена для минимизации рисков при его компрометации.
  • Алгоритм подписи: Используйте надежные алгоритмы (HS256, RS256) и убедитесь, что сервер проверяет именно тот алгоритм, который ожидается.
  • Валидация: Всегда валидируйте все необходимые поля в Payload (например, exp, nbf, iss, aud).
  • Отзыв токенов: JWT по своей природе stateless, что затрудняет их отзыв до истечения срока. Для реализации отзыва часто используются черные списки (blacklists) или короткие сроки жизни токенов с механизмом refresh-токенов.