Mehrere Authentifizierungsanbieter in Spring Security

1. Übersicht

In diesem kurzen Artikel konzentrieren wir uns auf die Verwendung mehrerer Mechanismen zur Authentifizierung von Benutzern in Spring Security.

Dazu konfigurieren wir mehrere Authentifizierungsanbieter.

2. Authentifizierungsanbieter

Ein AuthenticationProvider ist eine Abstraktion zum Abrufen von Benutzerinformationen aus einem bestimmten Repository (z. B. einer Datenbank, LDAP, einer benutzerdefinierten Quelle eines Drittanbieters usw.). Es verwendet die abgerufenen Benutzerinformationen, um die angegebenen Anmeldeinformationen zu überprüfen.

Einfach ausgedrückt, wenn mehrere Authentifizierungsanbieter definiert sind, werden die Anbieter in der Reihenfolge abgefragt, in der sie deklariert sind.

Für eine kurze Demonstration konfigurieren wir zwei Authentifizierungsanbieter - einen benutzerdefinierten Authentifizierungsanbieter und einen In-Memory-Authentifizierungsanbieter.

3. Maven-Abhängigkeiten

Fügen wir zunächst die erforderlichen Spring Security-Abhängigkeiten zu unserer Webanwendung hinzu:

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

Und ohne 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 

Die neueste Version dieser Abhängigkeiten finden Sie unter spring-security-web, spring-security-core und spring-security-config.

4. Benutzerdefinierter Authentifizierungsanbieter

Erstellen wir nun einen benutzerdefinierten Authentifizierungsanbieter, indem wir die AuthneticationProvider- Schnittstelle implementieren .

Wir werden die Authentifizierungsmethode implementieren, die die Authentifizierung versucht. Das eingegebene Authentifizierungsobjekt enthält die vom Benutzer angegebenen Anmeldeinformationen für Benutzername und Kennwort.

Die Authentifizierungsmethode gibt ein vollständig ausgefülltes Authentifizierungsobjekt zurück , wenn die Authentifizierung erfolgreich ist. Wenn die Authentifizierung fehlschlägt, wird eine Ausnahme vom Typ AuthenticationException ausgelöst :

@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); } }

Dies ist natürlich eine einfache Implementierung für den Zweck unseres Beispiels hier.

5. Mehrere Authentifizierungsanbieter konfigurieren

Fügen wir nun den CustomAuthenticationProvider und einen In-Memory-Authentifizierungsanbieter zu unserer Spring Security-Konfiguration hinzu.

5.1. Java-Konfiguration

In unserer Konfigurationsklasse erstellen und fügen wir nun die Authentifizierungsanbieter mithilfe des AuthenticationManagerBuilder hinzu und fügen sie hinzu .

Zuerst den CustomAuthenticationProvider und dann einen speicherinternen Authentifizierungsanbieter mithilfe von inMemoryAuthentication () .

Wir stellen außerdem sicher, dass der Zugriff auf das URL-Muster " / api / ** " authentifiziert werden muss:

@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-Konfiguration

Wenn Sie alternativ die XML-Konfiguration anstelle der Java-Konfiguration verwenden möchten:

6. Die Anwendung

Als Nächstes erstellen wir einen einfachen REST-Endpunkt, der von unseren beiden Authentifizierungsanbietern gesichert wird.

Um auf diesen Endpunkt zugreifen zu können, müssen ein gültiger Benutzername und ein gültiges Kennwort angegeben werden. Unsere Authentifizierungsanbieter überprüfen die Anmeldeinformationen und bestimmen, ob der Zugriff zugelassen werden soll oder nicht:

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

7. Testen

Lassen Sie uns abschließend den Zugriff auf unsere sichere Anwendung testen. Der Zugriff ist nur zulässig, wenn gültige Anmeldeinformationen angegeben sind:

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

In diesem kurzen Tutorial haben wir gesehen, wie mehrere Authentifizierungsanbieter in Spring Security konfiguriert werden können. Wir haben eine einfache Anwendung mit einem benutzerdefinierten Authentifizierungsanbieter und einem In-Memory-Authentifizierungsanbieter gesichert.

Außerdem haben wir Tests geschrieben, um zu überprüfen, ob für den Zugriff auf unsere Anwendung Anmeldeinformationen erforderlich sind, die von mindestens einem unserer Authentifizierungsanbieter überprüft werden können.

Wie immer finden Sie den vollständigen Quellcode der Implementierung auf GitHub.