Spring Boot
2026-02-26 19:54 Diff

Аутентификация — это проверка подлинности. Например, программа может проверить, действительно ли пользователь является тем, за кого себя выдает. Мы все участвуем в этом процессе, когда заполняем формы логинов и паролей. Spring Boot отвечает за реализацию этого процесса со стороны бэкенда.

В отличие от всех остальных эндпоинтов API, аутентификация в Spring Boot работает не сама по себе. Чтобы работать с ней, нам придется использовать достаточно навороченный пакет Spring Security. Этот пакет предоставляет множество готовых компонентов, но требует тонкой настройки. Это большая и сложная тема, по которой пишутся целые книги. Глубокое изучение Spring Security — это слишком сложно, и в этом курсе мы не будем погружаться в эту тему. Поэтому большую часть кода в этом уроке мы рассмотрим без подробного объяснения.

Все события во время аутентификации можно разделить на два уровня:

  • Пользователь и его функциональность. Сюда входит все от регистрации до проверки доступов. Чтобы работать с этим уровнем, нужно взять представленный в Spring Boot набор интерфейсов и реализовать его — тогда часть нужной функциональности начнет работать автоматически
  • Конкретный способ аутентификации. В зависимости от способа аутентификации мы можем использовать разные механизмы и сторонние пакеты — например, OAuth или JWT-токены

В этом уроке мы последовательно пройдем по всем частям системы и настроим их. Для аутентификации мы будем использовать JWT-токены. Во время логина система будет формировать JWT-токен, который вернется клиенту. Клиент будет пользоваться этим токеном для последующих запросов, иначе ему будет отказано в доступе.

Установка зависимостей

Помимо Spring Security, нам понадобятся пакет для тестирования и пакет oauth2-resource-server, который выполняет большую часть логики по проверке доступа внутри себя:

Настройка процесса аутентификации

Для аутентификации пользователя понадобится два поля:

  • email — это самый частый логин, кроме него иногда используют номер телефона или никнейм
  • passwordDigest — это специальный хэш, связанный с паролем. Мы храним именно хэш, а не сам пароль, потому что с точки зрения безопасности, пароли хранить в базе данных нельзя. Чтобы не запутаться, мы назвали это поле passwordDigest, а не password

Внутри себя Spring Security работает с интерфейсом UserDetails, в который входят методы для работы с никнеймом, паролем и выдачей доступов. Сейчас мы реализуем только аутентификацию, поэтому нас интересует только часть методов. Остальные методы мы тоже реализуем, но после базовой функциональности:

Обычно Spring Security работает с username, но под ним может скрываться что-то другое. Например, в нашем случае геттер возвращает email. Кроме того, вместо пароля мы получаем passwordDigest. Здесь все тоже корректно, потому что сравнение будет происходить с хэшем, а не с введенным пользователем паролем.

Далее мы создадим сервис, реализующий интерфейс UserDetailsManager. Через него Spring Boot будет выполнять CRUD-операции над пользователем. Для аутентификации реализуем метод loadUserByUsername():

Дальше нам понадобится механизм хеширования пароля. Чтобы работать с ним, создадим бин:

Теперь собираем все вместе. Указываем, что Spring Security должен использовать наши компоненты:

Мы сделали почти всю подготовительную работу. Осталось создать утилиту для генерации JWT-токена, и мы будем готовы реализовать аутентификацию.

Генерация состоит из двух вещей — подготовки токена и его шифрования. Рассмотрим пример класса, который делает эти операции:

В коде выше используется JwtEncoder. Он добавляется в класс EncodersConfig, в который мы уже добавили PasswordEncoder:

Для работы JwtEncoderнужны RSA-ключи — их можно сгенерировать, выполнив в терминале команды:

Затем мы должны зайти в application.yml и указать путь к ключам. Например, вот так:

Дальше мы создаем компонент, который прочитает эти ключи и сделает их доступными в коде:

Не забудьте, что в реальных проектах хранить приватный ключ в репозитории нельзя. Доступ к приватному ключу должен быть ограничен.

В нашем случае аутентификация — это обычный POST-запрос, в котором передаются электронная почта и пароль. Для унификации с предыдущими настройками, мы будем использовать имя username вместо почты email. В итоге у нас получится такой DTO:

Наконец, перейдем к контроллеру:

Все проделанные шаги свелись к строчке authenticationManager.authenticate(authentication). В итоге внутри кода выполняется поиск пользователя в базе данных, хэширование пароля и сравнение. Если аутентификация прошла, выполнение продолжается дальше, если нет — код выбрасывает исключение.

После аутентификации программа генерирует токен и возвращает его клиенту. С этого момента клиент сам следит за отправкой токена в последующих запросах к API. При этом мы должны убрать API из публичного доступа и включить проверку токена.

Проверка наличия аутентификации

Проверка аутентификации настраивается в конфигурации, помеченной аннотацией @EnableWebSecurity. Выше мы уже создали такой класс, добавив туда конфигурацию провайдера и менеджера аутентификации. Теперь добавим туда фильтр, который применяется ко всем входящим запросам:

Извлечение текущего пользователя

Кроме проверки доступа, в коде может понадобиться пользователь, выполняющий запрос. Например, такое бывает нужно, когда создается какая-то сущность, у которой есть автор. В таком случае автор почти всегда тот, кто выполняет запрос. Spring Security предоставляет возможность извлечь его из контекста:

Этот класс позволяет получать пользователя в контроллере одним вызовом.