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

Несколько поставщиков аутентификации в Spring Security

Узнайте, как использовать несколько поставщиков проверки подлинности в Spring Security.

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

1. Обзор

В этой краткой статье мы сосредоточимся на использовании нескольких механизмов аутентификации пользователей в Spring Security.

Мы сделаем это, настроив несколько поставщиков аутентификации.

2. Поставщики аутентификации

Поставщик аутентификации – это абстракция для извлечения информации о пользователе из определенного репозитория (например, база данных , LDAP , пользовательский сторонний источник и т. Д. ). Он использует полученную информацию о пользователе для проверки предоставленных учетных данных.

Проще говоря, когда определено несколько поставщиков аутентификации, поставщики будут запрашиваться в том порядке, в котором они объявлены.

Для быстрой демонстрации мы настроим два поставщика проверки подлинности – пользовательский поставщик проверки подлинности и поставщик проверки подлинности в памяти.

3. Зависимости Maven

Давайте сначала добавим необходимые зависимости безопасности Spring в наше веб-приложение:


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.boot
    spring-boot-starter-security

И, без Пружинного Ботинка:


    org.springframework.security
    spring-security-web
    5.2.2.RELEASE


    org.springframework.security
    spring-security-core
    5.2.2.RELEASE


    org.springframework.security
    spring-security-config
    5.2.2.RELEASE

Последнюю версию этих зависимостей можно найти в spring-security-web , spring-security-core и spring-security-config .

4. Пользовательский поставщик аутентификации

Теперь давайте создадим пользовательский поставщик аутентификации, реализовав Поставщик аутентификации интерфейс .

Мы собираемся реализовать метод authenticate , который пытается выполнить аутентификацию. Объект input Authentication содержит учетные данные имени пользователя и пароля, предоставленные пользователем.

Метод authenticate возвращает полностью заполненный объект Authentication , если аутентификация прошла успешно. Если проверка подлинности завершается неудачно, она создает исключение типа AuthenticationException :

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication auth) 
      throws AuthenticationException {
        String username = auth.getName();
        String password = auth.getCredentials()
            .toString();

        if ("externaluser".equals(username) && "pass".equals(password)) {
            return new UsernamePasswordAuthenticationToken
              (username, password, Collections.emptyList());
        } else {
            throw new 
              BadCredentialsException("External system authentication failed");
        }
    }

    @Override
    public boolean supports(Class auth) {
        return auth.equals(UsernamePasswordAuthenticationToken.class);
    }
}

Естественно, это простая реализация для целей нашего примера здесь.

5. Настройка Нескольких Поставщиков Аутентификации

Теперь давайте добавим Пользовательский поставщик аутентификации и поставщик аутентификации в памяти в нашу конфигурацию безопасности Spring.

5.1. Конфигурация Java

В нашем классе конфигурации давайте теперь создадим и добавим поставщиков аутентификации с помощью AuthenticationManagerBuilder .

Сначала Пользовательский поставщик аутентификации , а затем поставщик аутентификации в памяти с помощью inMemoryAuthentication() .

Мы также удостоверяемся, что доступ к шаблону URL ” /api/** ” должен быть аутентифицирован:

@EnableWebSecurity
public class MultipleAuthProvidersSecurityConfig 
  extends WebSecurityConfigurerAdapter {
    @Autowired
    CustomAuthenticationProvider customAuthProvider;

    @Override
    public void configure(AuthenticationManagerBuilder auth) 
      throws Exception {

        auth.authenticationProvider(customAuthProvider);
        auth.inMemoryAuthentication()
            .withUser("memuser")
            .password(encoder().encode("pass"))
            .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic()
            .and()
            .authorizeRequests()
            .antMatchers("/api/**")
            .authenticated();
    }
    
     
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

5.2. Конфигурация XML

В качестве альтернативы, если мы хотим использовать конфигурацию XML вместо конфигурации Java:


    
        
            
        
    
    



    
    

6. Приложение

Затем давайте создадим простую конечную точку REST, защищенную нашими двумя поставщиками аутентификации.

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

@RestController
public class MultipleAuthController {
    @GetMapping("/api/ping")
    public String getPing() {
        return "OK";
    }
}

7. Тестирование

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

@Autowired
private TestRestTemplate restTemplate;

@Test
public void givenMemUsers_whenGetPingWithValidUser_thenOk() {
    ResponseEntity result 
      = makeRestCallToGetPing("memuser", "pass");

    assertThat(result.getStatusCodeValue()).isEqualTo(200);
    assertThat(result.getBody()).isEqualTo("OK");
}

@Test
public void givenExternalUsers_whenGetPingWithValidUser_thenOK() {
    ResponseEntity result 
      = makeRestCallToGetPing("externaluser", "pass");

    assertThat(result.getStatusCodeValue()).isEqualTo(200);
    assertThat(result.getBody()).isEqualTo("OK");
}

@Test
public void givenAuthProviders_whenGetPingWithNoCred_then401() {
    ResponseEntity result = makeRestCallToGetPing();

    assertThat(result.getStatusCodeValue()).isEqualTo(401);
}

@Test
public void givenAuthProviders_whenGetPingWithBadCred_then401() {
    ResponseEntity result 
      = makeRestCallToGetPing("user", "bad_password");

    assertThat(result.getStatusCodeValue()).isEqualTo(401);
}

private ResponseEntity 
  makeRestCallToGetPing(String username, String password) {
    return restTemplate.withBasicAuth(username, password)
      .getForEntity("/api/ping", String.class, Collections.emptyMap());
}

private ResponseEntity makeRestCallToGetPing() {
    return restTemplate
      .getForEntity("/api/ping", String.class, Collections.emptyMap());
}

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

В этом кратком руководстве мы рассмотрели, как можно настроить несколько поставщиков аутентификации в Spring Security. Мы защитили простое приложение с помощью пользовательского поставщика аутентификации и поставщика аутентификации в памяти.

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

Как всегда, полный исходный код реализации можно найти на GitHub .