Какую проблему решает JWT-токен в распределённых системах?

Ответ

JWT (JSON Web Token) решает проблему stateless-аутентификации и авторизации в распределённых системах (микросервисах, API).

Проблема без JWT: Серверу необходимо хранить сессию пользователя (в памяти или БД), что усложняет масштабирование и создаёт точку отказа.

Решение с JWT: Токен сам содержит всю необходимую информацию (claims) и криптографическую подпись. Любой сервис, имеющий секретный ключ (или публичный ключ для RSA), может проверить его подлинность без обращения к центральной базе данных.

Структура JWT: Header.Payload.Signature

  • Header: Алгоритм подписи и тип токена.
  • Payload (Утверждения): Данные (например, sub (subject), exp (expiration), кастомные поля role).
  • Signature: Гарантирует, что токен не был изменён.

Пример создания и проверки (Java с библиотекой jjwt):

// Создание токена
String secret = "mySecretKey";
String token = Jwts.builder()
    .setSubject("user456")
    .claim("role", "ADMIN")
    .setExpiration(Date.from(Instant.now().plus(Duration.ofHours(1))))
    .signWith(SignatureAlgorithm.HS256, secret.getBytes())
    .compact();

// Проверка токена на другом сервисе
Claims claims = Jwts.parser()
    .setSigningKey(secret.getBytes())
    .parseClaimsJws(token)
    .getBody();

String username = claims.getSubject(); // "user456"
String role = claims.get("role", String.class); // "ADMIN"

Ключевые преимущества:

  • Масштабируемость: Отсутствие состояния на сервере.
  • Самостоятельность: Токен содержит все данные для авторизации.
  • Безопасность: Подпись защищает от подделки (но токен можно перехватить — всегда используйте HTTPS).

Важно: JWT не шифрует payload по умолчанию (используйте JWE для шифрования). Для немедленного отзыва токенов требуется дополнительная инфраструктура (чёрные списки).

Ответ 18+ 🔞

А, ну это ж про эти ваши JWT, блядь! Слушай, история-то простая, как три копейки, но без неё в современных системах — просто пиздец, а не жизнь.

В чём, сука, была проблема-то раньше?
Представь: зашёл пользователь, сервер ему говорит «окей, чувак», и должен где-то запомнить, что ты — это ты. Записывает тебя в свою память или в базу, создаёт сессию. А потом у тебя сервисов — овердохуища, микросервисы там, облака, хуйня. И каждый раз, когда ты к другому сервису идёшь, тот бежит проверять: «А кто это там? А он у нас в сессии есть?». И получается бардак, блядь, точка отказа, масштабирование — ну его в пизду, всё через одно место.

А тут приходит JWT, как слон в посудной лавке, только аккуратный.
Суть в том, что теперь сервер не хранит нихуя о тебе. Вообще. Всю нужную инфу он зашивает прямо в токен, как в консервную банку, и даёт тебе в руки. А сам токен — он с криптографической подписью, блядь. Любой другой сервис, у которого есть секретный ключ (или публичный, если по RSA), может проверить: а не пизжёшь ли ты, дружок? И всё — без беготни в общую базу, без вопросов «а помнишь меня, сука?».

Из чего этот JWT состоит, ёпта?
Три части, склеенные точками: Header.Payload.Signature.

  • Header — там тип токена и алгоритм подписи (HS256, RS512, ну ты понял).
  • Payload (утверждения) — вот тут вся соль, блядь: кто ты (sub), когда токен сдохнет (exp), какие права есть (role, например). Можно свои поля пихать.
  • Signature — это магия, которая не даёт всяким пидарасам подделать токен. Подписывается всё предыдущее говно секретным ключом.

Смотри, как это в коде выглядит (Java, библиотека jjwt):

// Делаем токен, будто печем пирожок
String secret = "mySecretKey";
String token = Jwts.builder()
    .setSubject("user456") // Кто ты?
    .claim("role", "ADMIN") // Ах ты, администратор, блядь!
    .setExpiration(Date.from(Instant.now().plus(Duration.ofHours(1)))) // Через час — в утиль
    .signWith(SignatureAlgorithm.HS256, secret.getBytes()) // Подписываем, чтоб не подделали
    .compact();

// А вот на другом сервисе проверяем, не левая ли хрень
Claims claims = Jwts.parser()
    .setSigningKey(secret.getBytes()) // Тот же ключ, сука
    .parseClaimsJws(token) // Парсим и проверяем подпись
    .getBody();

String username = claims.getSubject(); // "user456"
String role = claims.get("role", String.class); // "ADMIN" — о, важная птица!

Что хорошего-то, блядь?

  • Масштабируется нахуй — серверы не держат состояние, плоди их как кроликов.
  • Самостоятельный — токен сам всё про себя рассказывает.
  • Безопасный — подпись не даст его подделать (но если перехватят по HTTP — пиши пропало, всегда используй HTTPS, ебаный в рот!).

Но и подводные камни есть, как без них:
JWT по умолчанию не шифрует payload, только подписывает. Все твои поля внутри видны, если раскодировать base64. Хочешь секретность — юзай JWE (это уже шифрование).
И ещё: если токен украли — отозвать его сразу не выйдет, живёт себе до экспирации. Придётся заводить чёрные списки, а это уже сложности, блядь. Так что думай головой, где это применять.