JWT: структура, создание и проверка
Вручную декодируйте структуру JWT, создавайте подписанные секретом токены и проверяйте утверждения без фреймворков.
«JWT: структура, создание и проверка» — бесплатный урок Java Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Что такое JWT
JSON Web Token (JWT) — это компактный безопасный для URL формат токенов, предназначенный для передачи утверждений между сторонами. JWT подписывается, а при необходимости и шифруется. Он самодостаточен — для проверки утверждений не требуется обращаться к базе данных.
Структура JWT: Header.Payload.Signature
JWT состоит из трёх частей, закодированных в Base64URL и разделённых точками: header.payload.signature. В заголовке указывается алгоритм. Полезная нагрузка содержит утверждения. Подпись проверяет целостность.
// Example JWT:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 <- header
// .eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0 <- payload
// .SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c <- signatureДекодирование заголовка и полезной нагрузки
Декодируйте каждую часть с помощью Base64URL, чтобы увидеть JSON. Полезная нагрузка содержит «утверждения» — стандартные из них: sub (субъект), iss (издатель), exp (срок действия), iat (время выпуска).
// Header:
{ "alg": "HS256", "typ": "JWT" }
// Payload:
{ "sub": "user-42", "name": "Alice", "role": "ADMIN",
"iat": 1716000000, "exp": 1716003600 }Создание JWT вручную (HS256)
Сформируйте JSON заголовка и полезной нагрузки, закодируйте каждый из них в Base64URL, объедините точкой, затем вычислите HMAC-SHA256 для header.payload и добавьте результат как подпись.
String header = Base64.getUrlEncoder().withoutPadding()
.encodeToString("{\"alg\":\"HS256\",\"typ\":\"JWT\"}".getBytes());
String payload = Base64.getUrlEncoder().withoutPadding()
.encodeToString("{\"sub\":\"user-42\",\"exp\":9999999999}".getBytes());
String sigInput = header + "." + payload;
byte[] sig = computeHmac(secretKey, sigInput);
String jwt = sigInput + "." + Base64.getUrlEncoder().withoutPadding().encodeToString(sig);Проверка JWT вручную
Разделите строку по точкам, декодируйте заголовок и полезную нагрузку, повторно вычислите HMAC для header.payload, сравните его с подписью и проверьте, что срок действия exp ещё не истёк.
String[] parts = jwt.split("\\.");
String sigInput = parts[0] + "." + parts[1];
byte[] expectedSig = computeHmac(secretKey, sigInput);
byte[] actualSig = Base64.getUrlDecoder().decode(parts[2]);
if (!MessageDigest.isEqual(expectedSig, actualSig)) throw new SecurityException("Invalid signature");
// Decode payload and check exp:
String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]));
// parse JSON and check exp > nowИспользование библиотеки java-jwt (Auth0)
Библиотека com.auth0:java-jwt упрощает создание и проверку JWT с помощью гибкого API.
// Create:
Algorithm alg = Algorithm.HMAC256(secretKey);
String token = JWT.create()
.withSubject("user-42")
.withClaim("role", "ADMIN")
.withExpiresAt(Instant.now().plusSeconds(3600))
.sign(alg);
// Verify:
JWTVerifier verifier = JWT.require(alg).withIssuer("my-service").build();
DecodedJWT decoded = verifier.verify(token);
System.out.println(decoded.getSubject());HS256 и RS256
HS256 использует общий симметричный ключ — это просто, но и издатель, и проверяющая сторона должны доверять друг другу этот ключ. RS256 использует RSA: подпись создаётся закрытым ключом, а проверяется открытым — это подходит для архитектур из нескольких сервисов, где любой сервис может проверить подпись, не зная ключ подписания.
Хранение JWT: cookies HttpOnly и localStorage
Храните JWT в cookies HttpOnly (они недоступны из JS, что предотвращает их кражу через XSS), установив флаги Secure и SameSite=Strict. Избегайте localStorage — атаки XSS позволяют прочитать его содержимое.
// Set JWT as HttpOnly cookie in Spring:
ResponseCookie cookie = ResponseCookie.from("jwt", token)
.httpOnly(true).secure(true).sameSite("Strict")
.path("/").maxAge(3600).build();
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());Токены обновления
JWT имеют короткий срок действия (15 минут). Токены обновления (непрозрачные токены, хранящиеся на сервере) действуют дольше. Клиент обменивает токен обновления на новый JWT без повторной аутентификации.
Проблема отзыва JWT
JWT не хранят состояние — встроенного механизма отзыва нет. Используйте короткий срок действия и список заблокированных идентификаторов JWT (утверждение jti) в Redis, чтобы поддерживать выход из системы до истечения срока действия.
// On logout, add the jti to a Redis blocklist with TTL = token expiry:
redis.set("revoked:" + jti, "1", ex, 3600);
// On verify, check blocklist:
if (redis.exists("revoked:" + decoded.getId())) throw new SecurityException("Token revoked");Интеграция JWT со Spring Security
В Spring Security реализуйте JwtAuthenticationFilter extends OncePerRequestFilter, чтобы извлекать и проверять JWT, а затем устанавливать SecurityContext для каждого запроса.
String token = request.getHeader("Authorization").replace("Bearer ","");
DecodedJWT decoded = verifier.verify(token);
String userId = decoded.getSubject();
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(userId, null, authorities);
SecurityContextHolder.getContext().setAuthentication(auth);Быстрая проверка
В чём заключается ключевое структурное различие между подписанием JWT с помощью HS256 и RS256?
Итоги
JWT = header.payload.signature (Base64URL). Подписывайте с помощью HMAC (HS256) или RSA (RS256). Проверяйте подпись и утверждение exp. Храните JWT в cookies HttpOnly. Используйте короткий срок действия и токены обновления. Отзывайте токены с помощью списка заблокированных идентификаторов jti в Redis.
Часто задаваемые вопросы
Урок «JWT: структура, создание и проверка» бесплатный?
Да — полный текст урока «JWT: структура, создание и проверка» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «JWT: структура, создание и проверка»?
Вручную декодируйте структуру JWT, создавайте подписанные секретом токены и проверяйте утверждения без фреймворков. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «JWT: структура, создание и проверка»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Криптографическое хеширование с MessageDigest
- Симметричное шифрование AES
- HMAC-SHA256 для целостности сообщений
- JWT: структура, создание и проверка