Рубрики
Без рубрики

Руководство по распознавателю диспетчера аутентификации в Spring Security

Узнайте, как использовать распознаватель диспетчера проверки подлинности Spring Security для потоков проверки подлинности Basic и OAuth2

Автор оригинала: baeldung.

1. введение

В этом учебном пособии мы представим Authentication Manager Resolver , а затем покажем, как использовать его для потоков аутентификации Basic и OAuth2.

2. Что такое Менеджер Аутентификации?

Проще говоря, Authentication Manager является основным стратегическим интерфейсом для аутентификации.

Если принципал входной аутентификации действителен и проверен, AuthenticationManager#authenticate возвращает экземпляр Authentication с флагом authenticated , установленным в true . В противном случае, если принципал недействителен, он вызовет исключение AuthenticationException . В последнем случае он возвращает null , если не может решить.

ProviderManager является реализацией по умолчанию Authentication Manager . Он делегирует процесс проверки подлинности списку экземпляров Поставщика проверки подлинности|/.

Мы можем настроить глобальный или локальный Диспетчер аутентификации , если мы расширим WebSecurityConfigurerAdapter . Для локального AuthenticationManager мы могли бы переопределить configure(AuthenticationManagerBuilder) .

AuthenticationManagerBuilder – это вспомогательный класс, который упрощает настройку Userdetailsservice , Поставщика аутентификации и других зависимостей для создания AuthenticationManager .

Для глобального Диспетчера аутентификации мы должны определить Диспетчер аутентификации как компонент.

3. Почему распознаватель диспетчера аутентификации?

Распознаватель диспетчера аутентификации позволяет Spring выбрать Диспетчер аутентификации для каждого контекста. Это новая функция добавлена в Spring Security в версии 5.2.0:

public interface AuthenticationManagerResolver {
    AuthenticationManager resolve(C context);
}

Распознаватель диспетчера аутентификации#resolve может возвращать экземпляр Диспетчера аутентификации на основе общего контекста. Другими словами , мы можем установить класс в качестве контекста, если мы хотим разрешить Диспетчер аутентификации в соответствии с ним.

Spring Security интегрировала Распознаватель диспетчера аутентификации в потоке аутентификации с HttpServletRequest и Сервер Веб-обмена как контекст.

4. Сценарий использования

Давайте посмотрим, как использовать Authentication Manager/| на практике.

Например, предположим, что в системе есть две группы пользователей: сотрудники и клиенты. Эти две группы имеют определенную логику аутентификации и имеют отдельные хранилища данных. Кроме того, пользователям в любой из этих групп разрешено вызывать только связанные с ними URL-адреса.

5. Как Работает Распознаватель Диспетчера Аутентификации?

Мы можем использовать Authentication Manager Resolver везде, где нам нужно выбрать Authentication Manager динамически, но в этом руководстве мы заинтересованы в его использовании во встроенных потоках аутентификации.

Во-первых, давайте настроим распознаватель Authentication Manager , а затем используем его для аутентификации Basic и OAuth2.

5.1. Настройка Распознавателя Диспетчера Аутентификации

Давайте начнем с создания класса для настройки безопасности. Мы должны расширить WebSecurityConfigurerAdapter :

@Configuration
public class CustomWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    // ...
}

Затем давайте добавим метод, который возвращает Диспетчер аутентификации для клиентов:

AuthenticationManager customersAuthenticationManager() {
    return authentication -> {
        if (isCustomer(authentication)) {
            return new UsernamePasswordAuthenticationToken(/*credentials*/);
        }
        throw new UsernameNotFoundException(/*principal name*/);
    };
}

Менеджер аутентификации для сотрудников логически одинаков, только мы заменяем Клиент на Сотрудник :

public AuthenticationManager employeesAuthenticationManager() {
    return authentication -> {
        if (isEmployee(authentication)) {
            return new UsernamePasswordAuthenticationToken(/*credentials*/);
        }
        throw new UsernameNotFoundException(/*principal name*/);
    };
}

Наконец, давайте добавим распознаватель Authentication Manager , который разрешает в соответствии с URL-адресом запроса:

AuthenticationManagerResolver resolver() {
    return request -> {
        if (request.getPathInfo().startsWith("/employee")) {
            return employeesAuthenticationManager();
        }
        return customersAuthenticationManager();
    };
}

5.2. Для Базовой Аутентификации

Мы можем использовать Фильтр аутентификации для динамического разрешения Диспетчера аутентификации по запросу. Фильтр аутентификации был добавлен в Spring Security в версии 5.2.

Если мы добавим его в нашу цепочку фильтров безопасности, то для каждого совпадающего запроса он сначала проверяет, может ли он извлечь какой-либо объект аутентификации или нет. Если да, то он запрашивает у распознавателя Authentication Manager подходящий Authentication Manager и продолжает поток.

Во-первых, давайте добавим метод в наш Пользовательский WebSecurityConfigurer для создания Фильтра аутентификации :

private AuthenticationFilter authenticationFilter() {
    AuthenticationFilter filter = new AuthenticationFilter(
      resolver(), authenticationConverter());
    filter.setSuccessHandler((request, response, auth) -> {});
    return filter;
}

Причина установки Фильтр аутентификации#successHandler с отказом от операции Обработчик успеха это делается для предотвращения поведения перенаправления по умолчанию после успешной аутентификации.

Затем мы можем добавить этот фильтр в нашу цепочку фильтров безопасности, переопределив WebSecurityConfigurerAdapter#configure(HttpSecurity) в нашем CustomWebSecurityConfigurer :

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(
      authenticationFilter(),
      BasicAuthenticationFilter.class);
}

5.3. Для аутентификации OAuth2

Фильтр аутентификации токенов на предъявителя отвечает за аутентификацию OAuth2. Метод Bearer Token Authentication Filter#doFilterInternal проверяет наличие токена аутентификации Bearer Token в запросе, и если он доступен, то он разрешает соответствующий AuthenticationManager для аутентификации токена.

Конфигуратор сервера ресурсов OAuth2 используется для настройки фильтра аутентификации токенов на предъявителя .

Таким образом, мы можем настроить Распознаватель диспетчера аутентификации для нашего сервера ресурсов в нашем Пользовательском WebSecurityConfigurer , переопределив WebSecurityConfigurerAdapter#configure(HttpSecurity) :

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
      .oauth2ResourceServer()
      .authenticationManagerResolver(resolver());
}

6. Разрешите диспетчер аутентификации в реактивных приложениях

Для реактивного веб-приложения мы все еще можем извлечь выгоду из концепции разрешения Authentication Manager в соответствии с контекстом. Но здесь у нас есть Реактивный распознаватель AuthenticationManager вместо этого:

@FunctionalInterface
public interface ReactiveAuthenticationManagerResolver {
    Mono resolve(C context);
}

Он возвращает Mono из Reactive AuthenticationManager . Reactive AuthenticationManager является реактивным эквивалентом Authentication Manager , следовательно, его authenticate метод возвращает Mono .

6.1. Настройка Резольвера AuthenticationManager

Давайте начнем с создания класса для настройки безопасности:

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class CustomWebSecurityConfig {
    // ...
}

Далее, давайте определим Reactive AuthenticationManager для клиентов в этом классе:

ReactiveAuthenticationManager customersAuthenticationManager() {
    return authentication -> customer(authentication)
      .switchIfEmpty(Mono.error(new UsernameNotFoundException(/*principal name*/)))
      .map(b -> new UsernamePasswordAuthenticationToken(/*credentials*/));
}

И после этого мы определим Reactive AuthenticationManager для сотрудников:

public ReactiveAuthenticationManager employeesAuthenticationManager() {
    return authentication -> employee(authentication)
      .switchIfEmpty(Mono.error(new UsernameNotFoundException(/*principal name*/)))
      .map(b -> new UsernamePasswordAuthenticationToken(/*credentials*/));
}

Наконец, мы настроили Реактивный распознаватель AuthenticationManager на основе нашего сценария:

ReactiveAuthenticationManagerResolver resolver() {
    return exchange -> {
        if (match(exchange.getRequest(), "/employee")) {
            return Mono.just(employeesAuthenticationManager());
        }
        return Mono.just(customersAuthenticationManager());
    };
}

6.2. Для Базовой Аутентификации

В реактивном веб-приложении мы можем использовать Аутентификационный веб-фильтр для аутентификации. Он аутентифицирует запрос и заполняет контекст безопасности.

Веб-фильтр аутентификации сначала проверяет, соответствует ли запрос. После этого, если в запросе есть объект аутентификации, он получает подходящий Reactive AuthenticationManager для запроса от ReactiveAuthenticationManagerResolver и продолжает поток аутентификации.

Таким образом, мы можем настроить наш настраиваемый Веб-фильтр аутентификации в вашей конфигурации безопасности:

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
    return http
      .authorizeExchange()
      .pathMatchers("/**")
      .authenticated()
      .and()
      .httpBasic()
      .disable()
      .addFilterAfter(
        new AuthenticationWebFilter(resolver()), 
        SecurityWebFiltersOrder.REACTOR_CONTEXT
      )
      .build();
}

Сначала мы отключаем Server Http Security#http Basic , чтобы предотвратить обычный поток аутентификации, затем вручную заменяем его AuthenticationWebFilter , передавая наш пользовательский распознаватель.

6.3. Для аутентификации OAuth2

Мы можем настроить Реактивный распознаватель AuthenticationManager с помощью Server Http Security#oauth2 ResourceServer . Server Http Security#build добавляет экземпляр Аутентификационного веб-фильтра с нашим распознавателем в цепочку фильтров безопасности.

Итак, давайте установим наш Распознаватель диспетчера аутентификации для фильтра аутентификации OAuth2 в нашей конфигурации безопасности:

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
    return http
      // ...
      .and()
      .oauth2ResourceServer()
      .authenticationManagerResolver(resolver())
      .and()
      // ...;
}

7. Заключение

В этой статье мы использовали Authentication Manager Resolver для проверки подлинности Basic и OAuth2 в простом сценарии.

Кроме того, я также изучил использование Reactive AuthenticationManager Resolver в веб-приложениях reactive Spring как для базовой, так и для аутентификации OAuth2.

Как всегда, исходный код доступен на GitHub . Наш реактивный пример также доступен на GitHub .