Добавить в корзинуПозвонить
Найти в Дзене
Записки о Java

Spring Security + JWT: как реализовать аутентификацию с токенами в Java 11 (пошаговое руководство)

Целевая аудитория: Java-разработчики, использующие Java 11 и Spring Boot 2.7+, знакомые с основами Spring Security, но впервые работающие с JWT.
Цель статьи: показать полную и понятную реализацию JWT-аутентификации без внешних библиотек вроде Spring Security OAuth2 Resource Server (т.к. они требуют Java 17+), используя только jjwt и стандартные Spring-механизмы. JWT (JSON Web Token) — это открытый стандарт (RFC 7519) для безопасной передачи данных между сторонами в виде JSON-объекта. Он: В отличие от сессий (cookies), JWT — stateless: сервер не хранит информацию о токене, только проверяет его подпись. <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </depend
Оглавление
Рисунок: Spring Security+JWT
Рисунок: Spring Security+JWT

Целевая аудитория: Java-разработчики, использующие Java 11 и Spring Boot 2.7+, знакомые с основами Spring Security, но впервые работающие с JWT.
Цель статьи: показать полную и понятную реализацию JWT-аутентификации без внешних библиотек вроде Spring Security OAuth2 Resource Server (т.к. они требуют Java 17+), используя только jjwt и стандартные Spring-механизмы.

🔐 Что такое JWT и зачем он нужен?

JWT (JSON Web Token) — это открытый стандарт (RFC 7519) для безопасной передачи данных между сторонами в виде JSON-объекта. Он:

  • Самодостаточен: содержит в себе данные пользователя и метаданные (например, срок действия);
  • Подписывается: позволяет проверить подлинность и целостность данных;
  • Не требует хранения сессии на сервере — идеален для REST API и микросервисов.

В отличие от сессий (cookies), JWT — stateless: сервер не хранит информацию о токене, только проверяет его подпись.

⚙️ Технологический стек

  • Java 11 (важно! Spring Boot 3+ требует Java 17+)
  • Spring Boot 2.7.18 (последняя версия с поддержкой Java 11)
  • Spring Security
  • jjwt-api / jjwt-impl / jjwt-jackson — библиотека для работы с JWT
  • Maven

1. Зависимости (pom.xml)

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-security</artifactId>

</dependency>

<!-- JWT -->

<dependency>

<groupId>io.jsonwebtoken</groupId>

<artifactId>jjwt-api</artifactId>

<version>0.11.5</version>

</dependency>

<dependency>

<groupId>io.jsonwebtoken</groupId>

<artifactId>jjwt-impl</artifactId>

<version>0.11.5</version>

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>io.jsonwebtoken</groupId>

<artifactId>jjwt-jackson</artifactId>

<version>0.11.5</version>

<scope>runtime</scope>

</dependency>

</dependencies>

💡 Версия 0.11.5 совместима с Java 8+, включая Java 11.
Не используйте jjwt 0.12+ — он требует Java 17.

2. Структура проекта

src/

├── controller/

│ ├── AuthController.java // Эндпоинт /login

│ └── HelloController.java // Защищённый эндпоинт

├── security/

│ ├── JwtUtil.java // Генерация и валидация JWT

│ ├── JwtRequestFilter.java // Фильтр для проверки токена

│ └── SecurityConfig.java // Конфигурация Spring Security

├── model/

│ └── JwtRequest.java // DTO для входа

└── exception/

└── JwtAuthenticationException.java

3. Модели и исключения

JwtRequest.java — DTO для входа

Рисунок: класс JwtRequest
Рисунок: класс JwtRequest

JwtAuthenticationException.java

Рисунок: класс JwtAuthenticationException
Рисунок: класс JwtAuthenticationException

4. Утилита для работы с JWT

JwtUtil.java

Рисунок: клксс JwtUtil, часть 1
Рисунок: клксс JwtUtil, часть 1
Рисунок: класс JwtUtil, часть 2
Рисунок: класс JwtUtil, часть 2
Рисунок: класс JwtUtil, часть 3
Рисунок: класс JwtUtil, часть 3

Важно:

  • secret должен быть base64-закодированной строкой длиной ≥ 256 бит (32 байта).
  • В application.properties задайте:

jwt.secret=SGVsbG9Xb3JsZFNwcmluZ0pXVEpvd2FuQXV0aGVudGljYXRpb24= # "HelloWorldSpringJWTJowanAuthentication" в base64

jwt.expiration=86400000 # 24 часа в миллисекундах

5. Фильтр для обработки JWT

JwtRequestFilter.java

Рисунок: JwtRequestFilter, часть 1
Рисунок: JwtRequestFilter, часть 1
Рисунок: JwtRequestFilter, часть 2
Рисунок: JwtRequestFilter, часть 2

📌 Этот фильтр:

  • Извлекает токен из заголовка Authorization;
  • Проверяет его валидность;
  • Устанавливает Authentication в SecurityContext.

6. UserDetailsService — хранилище пользователей

Для примера — в памяти (в реальности — JPA репозиторий):

Рисунок: класс UserDetailsService
Рисунок: класс UserDetailsService

🔐 Важно:

  • Пароль должен быть зашифрован! Сгенерируйте BCrypt через онлайн-генератор или BCryptPasswordEncoder.
  • Добавьте бин PasswordEncoder в конфигурацию.

7. Конфигурация Spring Security

SecurityConfig.java

Рисунок: класс SecurityConfig, часть 1
Рисунок: класс SecurityConfig, часть 1
Рисунок: класс SecurityConfig, часть 2
Рисунок: класс SecurityConfig, часть 2

JwtAuthenticationEntryPoint.java — обработка ошибок аутентификации

Рисунок: класс JwtAuthenticationEntryPoint
Рисунок: класс JwtAuthenticationEntryPoint

8. Контроллеры

AuthController.java

Рисунок: класс AuthController
Рисунок: класс AuthController

JwtResponse.java

Рисунок: класс JwtResponse
Рисунок: класс JwtResponse

HelloController.java — защищённый эндпоинт

Рисунок: класс HelloController
Рисунок: класс HelloController

🔒 Безопасность: что улучшить в продакшене?

  • Храните jwt.secret в переменных окружения или Vault, не в коде;
  • Используйте refresh tokens для продления сессии;
  • Добавьте чёрный список токенов (Redis) при логауте;
  • Ограничьте IP-адреса, user-agent, время жизни;
  • Всегда используйте HTTPS.

📌 Заключение

JWT — мощный инструмент для stateless-аутентификации в REST API. С Spring Security и библиотекой jjwt вы можете реализовать его полностью на Java 11, без перехода на более новые версии JDK.