Più provider di autenticazione in Spring Security

1. Panoramica

In questo rapido articolo, ci concentreremo sull'utilizzo di più meccanismi per autenticare gli utenti in Spring Security.

Lo faremo configurando più provider di autenticazione.

2. Fornitori di autenticazione

Un AuthenticationProvider è un'astrazione per il recupero delle informazioni dell'utente da un repository specifico (come un database, LDAP, una fonte di terze parti personalizzata, ecc.). Utilizza le informazioni utente recuperate per convalidare le credenziali fornite.

In poche parole, quando vengono definiti più provider di autenticazione, i provider verranno interrogati nell'ordine in cui sono stati dichiarati.

Per una rapida dimostrazione, configureremo due provider di autenticazione: un provider di autenticazione personalizzato e un provider di autenticazione in memoria.

3. Dipendenze di Maven

Aggiungiamo prima le necessarie dipendenze di Spring Security nella nostra applicazione web:

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

E, senza Spring Boot:

 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 

L'ultima versione di queste dipendenze può essere trovata in spring-security-web, spring-security-core e spring-security-config.

4. Provider di autenticazione personalizzato

Creiamo ora un provider di autenticazione personalizzato implementando l' interfaccia AuthneticationProvider .

Implementeremo il metodo di autenticazione , che tenta l'autenticazione. L' oggetto di autenticazione di input contiene le credenziali di nome utente e password fornite dall'utente.

Il metodo di autenticazione restituisce un oggetto di autenticazione completamente popolato se l'autenticazione ha esito positivo. Se l'autenticazione fallisce, genera un'eccezione di tipo 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); } }

Naturalmente, questa è una semplice implementazione ai fini del nostro esempio qui.

5. Configurazione di più provider di autenticazione

Aggiungiamo ora CustomAuthenticationProvider e un provider di autenticazione in memoria alla nostra configurazione Spring Security.

5.1. Configurazione Java

Nella nostra classe di configurazione, creiamo e aggiungiamo ora i provider di autenticazione utilizzando AuthenticationManagerBuilder .

Innanzitutto, CustomAuthenticationProvider e quindi un provider di autenticazione in memoria utilizzando inMemoryAuthentication () .

Ci stiamo anche assicurando che l'accesso al pattern URL " / api / ** " debba essere autenticato:

@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. Configurazione XML

In alternativa, se vogliamo utilizzare la configurazione XML invece della configurazione Java:

6. L'applicazione

Successivamente, creiamo un semplice endpoint REST protetto dai nostri due provider di autenticazione.

Per accedere a questo endpoint, è necessario fornire un nome utente e una password validi. I nostri fornitori di autenticazione convalideranno le credenziali e determineranno se consentire o meno l'accesso:

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

7. Test

Infine, proviamo ora l'accesso alla nostra applicazione sicura. L'accesso sarà consentito solo se vengono fornite credenziali valide:

@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. Conclusione

In questo breve tutorial, abbiamo visto come è possibile configurare più provider di autenticazione in Spring Security. Abbiamo protetto una semplice applicazione utilizzando un provider di autenticazione personalizzato e un provider di autenticazione in memoria.

Inoltre, abbiamo scritto test per verificare che l'accesso alla nostra applicazione richieda credenziali che possano essere convalidate da almeno uno dei nostri fornitori di autenticazione.

Come sempre, il codice sorgente completo dell'implementazione può essere trovato su GitHub.