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-аутентификацию.

В общих чертах процесс аутентификации в Spring Security описан в статье "Аутентификация в Spring Security".
Basic-аутентификацию в Spring Security реализуют следующие стандартные компоненты:
BasicAuthenticationFilter- фильтр, инициирующий процесс аутентификации при наличии в HTTP-запросе заголовкаAuthorizationсо схемойBasicUsernamePasswordAuthenticationToken- класс, описывающий запрос и результат аутентификации по логину и паролюDaoAuthenticationProvider- провайдер аутентификации, обрабатывающийUsernamePasswordAuthenticationTokenUserDetailsService- сервис для получения данных по пользователе по логинуUserDetails- интерфейс, описывающий пользователя
Успешная аутентификация будет выглядеть следующим образом:

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

Стоит обратить внимание на компоненты, которые используются фильтром BasicAuthenticationFilter:
SecurityContextHolderStrategy- для доступа к контексту безопасностиAuthenticationEntryPoint- точка входа, используется в случае, если в процессе аутентификации возникла ошибка и требуется снова запросить у пользователя данные для аутентификацииAuthenticationManager- компонент, обрабатывающий запросы аутентификацииRememberMeServices- компонент для запоминания аутентифицированного пользователяBasicAuthenticationConverter- компонент, формирующий запрос на аутентификацию из данных, полученных из HTTP-запросаSecurityContextRepository- репозиторий контекстов безопасности
Настройка Basic-аутентификации
Для настройки Basic-аутентификации в настройках цепочки фильтров безопасности существует DSL-метод .httpBasic, который предоставляет следующие методы:
authenticationEntryPoint- для указания точки входа на случай ошибки аутентификации, по умолчанию это экземпляр классаBasicAuthenticationEntryPointauthenticationDetailsSource- для указания источника дополнительных данных запроса аутентификации (ip-адрес, идентификатор HTTP-сессии и т.д.), по умолчанию -WebAuthenticationDetailsSourcesecurityContextRepository- репозиторий контекстов безопасности, по умолчаниюRequestAttributeSecurityContextRepositoryrealmName- для указания названия источника пользователей. 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, но про это я расскажу в отдельном материале.
Понравилась статья? Тогда поддержки проект и подкинь монетку:
Больше полезных статей и роликов: