Вход по токену JWT
С Basic-входом пароль летит в каждом запросе. Обычно делают иначе: клиент один раз отправляет логин и пароль на адрес входа и получает токен — строку, которая подтверждает, кто он. Дальше клиент передаёт только токен в заголовке Authorization: Bearer .... Самый распространённый формат токена — JWT (JSON Web Token): три части через точку, в середине — данные о пользователе, в конце — подпись сервера. Подделать токен без секретного ключа нельзя.
Настройки
Модуль micronaut-security-jwt уже подключён в прошлом уроке. Добавьте две строки в настройки:
# src/main/resources/application.properties
micronaut.security.authentication=bearer
micronaut.security.token.jwt.signatures.secret.generator.secret=${JWT_SECRET:changemechangemechangemechangeme}Первая включает режим токенов: появляется адрес POST /login, а сервер принимает заголовок Bearer. Вторая задаёт секрет подписи. Запись ${JWT_SECRET:...} значит «взять из переменной окружения JWT_SECRET, а если её нет — значение после двоеточия». На сервере секрет задают только переменной.
BlogAuthenticationProvider из прошлого урока менять не нужно: /login проверяет логин и пароль через него же.
Получение токена
curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d '{"username":"oleg","password":"changeme"}'{"username":"oleg","roles":["AUTHOR"],"expires_in":3600,"access_token":"eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJibG9nIiwic3ViIjoib2xlZyIsIm5iZiI6MTc5MTEwNDk5OCwiZXhwIjoxNzkxMTA4NTk4LCJpYXQiOjE3OTExMDQ5OTgsInJvbGVzIjpbIkFVVEhPUiJdfQ.wmoVIAAmS-k5aPIKf9RS7Q9FUJEgsG5FVcWJMjojLFc","token_type":"Bearer"}Токен действует 3600 секунд — час. Средняя часть — это просто Base64, её можно прочитать:
{"iss":"blog","sub":"oleg","nbf":1791104998,"exp":1791108598,"iat":1791104998,"roles":["AUTHOR"]}sub — имя пользователя, roles — роли, exp — время окончания. Пароля в токене нет. Сервер не хранит выданные токены: он проверяет подпись и срок.
Запросы с токеном
Сохраните токен в переменную и передайте в заголовке:
TOKEN=eyJhbGciOiJIUzI1NiJ9...
curl -X POST http://localhost:8080/articles \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"С токеном","body":"Текст"}'{"id":1,"title":"С токеном","body":"Текст"}Правила @Secured из прошлого урока работают так же — роли берутся из токена. Контроллер /me с параметром Authentication покажет {"name":"oleg","roles":["AUTHOR"]}.
Ответы при ошибках
| Ситуация | Ответ |
|---|---|
Неверный пароль на /login | 401 Credentials Do Not Match |
| Нет токена, а метод требует входа | 401 Unauthorized |
| Токен испорчен или истёк | 401 Unauthorized |
| Токен верный, но роли не хватает | 403 Forbidden |
Частая ошибка
Алгоритм подписи HS256 требует секрет длиной не меньше 256 бит — 32 символа. С коротким секретом, например JWT_SECRET=changeme, приложение запускается, но /login отвечает 500 с пустым телом, а в журнале:
WARN i.m.s.t.j.g.JwtTokenGenerator - JOSEException while generating token The secret length must be at least 256 bitsИспользуйте длинную случайную строку и храните её вне репозитория.