Basic-аутентификация в Spring Security

Basic-аутентификация в Spring Security

Александр Косарев

Одним из наиболее простых способов аутентификации в HTTP является Basic-аутентификация. Данный способ аутентификации можно назвать универсальным, так как он может использоваться как на обычных сайтах, так и в сервисах, реализующих REST или SOAP. Кроме того Basic-аутентификацию можно использовать и в протоколах на основе HTTP, например в WebDAV.

В Spring Security есть поддержка Basic-аутентификации, и, более того, это один из основных способов аутентификации в Spring Security наравне с традиционной формой входа.

Как работает Basic-аутентификация

При использовании Basic-аутентификации клиент должен в числе заголовков HTTP-запроса указывать заголовок Authorization со схемой Basic и Base64-закодированной строкой, содержащей логин и пароль. В целом псевдокод заголовка выглядит так:

Authorization: Basic base64(username:password)

а реальный вид будет таким:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

С учётом того, что Base64-кодирование является обратимым, для HTTP-запросов должно применяться шифрование, во избежание утечки данных. Традиционно Basic-аутентификация применяется в сервисах без состояния (stateless), и процесс идентификации и аутентификации выполняется во время обработки каждого запроса. Впрочем, никто не мешает создавать HTTP-сессию при успешной Basic-аутентификации и использовать в дальнейшем её.

Для каких случаев подходит

Basic-аутентификацию следует применять в тех случаях, когда нужно реализовать сервис без хранения состояния (stateless). Наиболее удобно её применять для реализации межсервисного взаимодействия через протоколы SOAP, REST и других на основе HTTP.

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

Но в любом случае следует помнить, что Basic-аутентификацию можно использовать только при наличии шифрования.

Как устроена Basic-аутентификация в Spring Security

В случае, если не аутентифицированный пользователь пытается получить доступ к защищённому ресурсу, то будет выброшено исключение AccessDeniedException, в процессе обработки которого ExceptionTranslationFilter при помощи точки входа BasicAuthenticationEntryPoint вернёт пользователю HTTP-ответ со статусом 401 Unauthorized и заголовком WWW-Authenticate: Basic realm="Realm name". Такой ответ говорит клиенту, что ему необходимо использовать Basic-аутентификацию.

Инициация Basic-аутентификации

В общих чертах процесс аутентификации в Spring Security описан в статье "Аутентификация в Spring Security".

Basic-аутентификацию в Spring Security реализуют следующие стандартные компоненты:

  • BasicAuthenticationFilter - фильтр, инициирующий процесс аутентификации при наличии в HTTP-запросе заголовка Authorization со схемой Basic
  • UsernamePasswordAuthenticationToken - класс, описывающий запрос и результат аутентификации по логину и паролю
  • DaoAuthenticationProvider - провайдер аутентификации, обрабатывающий UsernamePasswordAuthenticationToken
  • UserDetailsService - сервис для получения данных по пользователе по логину
  • UserDetails - интерфейс, описывающий пользователя

Успешная аутентификация будет выглядеть следующим образом:

Успешная Basic-аутентификация

В случае, если пользователь ввёл неверные данные, BasicAuthenticationFilter может снова запросить логин и пароль у клиента при помощи точки входа BasicAuthenticationEntryPoint:

Ошибка при Basic-аутентификации

Стоит обратить внимание на компоненты, которые используются фильтром BasicAuthenticationFilter:

  • SecurityContextHolderStrategy - для доступа к контексту безопасности
  • AuthenticationEntryPoint - точка входа, используется в случае, если в процессе аутентификации возникла ошибка и требуется снова запросить у пользователя данные для аутентификации
  • AuthenticationManager - компонент, обрабатывающий запросы аутентификации
  • RememberMeServices - компонент для запоминания аутентифицированного пользователя
  • BasicAuthenticationConverter - компонент, формирующий запрос на аутентификацию из данных, полученных из HTTP-запроса
  • SecurityContextRepository - репозиторий контекстов безопасности

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

Для настройки Basic-аутентификации в настройках цепочки фильтров безопасности существует DSL-метод .httpBasic, который предоставляет следующие методы:

  • authenticationEntryPoint - для указания точки входа на случай ошибки аутентификации, по умолчанию это экземпляр класса BasicAuthenticationEntryPoint
  • authenticationDetailsSource - для указания источника дополнительных данных запроса аутентификации (ip-адрес, идентификатор HTTP-сессии и т.д.), по умолчанию - WebAuthenticationDetailsSource
  • securityContextRepository - репозиторий контекстов безопасности, по умолчанию RequestAttributeSecurityContextRepository
  • realmName - для указания названия источника пользователей. Realm - это некоторый источник пользователей, параметр realmName нужен, чтобы пользователю было понятно, из какого сервиса логин и пароль он должен вводить.

Отключить Basic-аутентификацию можно, как и другие DSL, при помощи метода disable.

Пример настройки Basic-аутентификации:

@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain(HttpSecurity http) throws Exception {
        var realmName = "localhost";
        var entryPoint= new BasicAuthenticationEntryPoint();
        entryPoint.setRealmName(realmName);
        return http.httpBasic(httpBasic ->
                // Realm
                httpBasic.realmName(realmName)
                    // Точка входа
                    .authenticationEntryPoint(entryPoint))
                    // Источник дополнительных параметров
                    .authenticationDetailsSource(new WebAuthenticationDetailsSource())
                    // Репозиторий контекстов безопасности
                    .securityContextRepository(
                            new RequestAttributeSecurityContextRepository())
                .build();
    }
}

Использование HTTP-сессии

По умолчанию при Basic-аутентификации в Spring Security не используется HTTP-сессия, т.к. данный способ аутентификации задумывался как альтернатива HTTP-сессиям. Но если вы всё же хотите использовать после успешной аутентификации HTTP-сессии, то это можно сделать следующим образом:

@Configuration
public class SecurityConfiguration {

  @Bean
  public SecurityFilterChain(HttpSecurity http) throws Exception {
    return http
            .httpBasic(httpBasic -> httpBasic
                .securityContextRepository(
                // Хранение контекста безопасности в HTTP-сессии
                new HttpSessionSecurityContextRepository()))
                // Создание HTTP-сессии при необходимости
                .sessionManagement(sessionManagement -> 
                  sessionManagement
                  .sessionCreationPolicy(SessionCreationPolicy.ALWAYS))
                .build();
    }
}

Однако запоминать пользователя можно и другим способом - при помощи функции RememberMe, но про это я расскажу в отдельном материале.

Понравилась статья? Тогда поддержки проект и подкинь монетку:

Больше полезных статей и роликов:

Report Page