Mehrere Authentifizierungsanbieter in Spring Security
1. Überblick
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
EinAuthenticationProvider ist eine Abstraktion zum Abrufen von Benutzerinformationen aus einem bestimmten Repository (wiedatabase,LDAP,custom third party source usw. ). Die abgerufenen Benutzerinformationen werden verwendet, 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.
Zur schnellen 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.0.4.RELEASE
org.springframework.security
spring-security-core
5.0.4.RELEASE
org.springframework.security
spring-security-config
5.0.4.RELEASE
Die neueste Version dieser Abhängigkeiten finden Sie unterspring-security-web,spring-security-core undspring-security-config.
4. Benutzerdefinierter Authentifizierungsanbieter
Erstellen Sie jetzt einen benutzerdefinierten Authentifizierungsanbieter, indem Sie dieAuthneticationProvider-Schnittstelle. implementieren
Wir werden dieauthenticate-Methode implementieren, mit der die Authentifizierung versucht wird. Das ObjektAuthenticationder Eingabe enthält den vom Benutzer angegebenen Benutzernamen und das Kennwort.
Die Methodeauthenticate gibt ein vollständig ausgefülltesAuthentication-Objekt zurück, wenn die Authentifizierung erfolgreich ist. Wenn die Authentifizierung fehlschlägt, wird eine Ausnahme vom TypAuthenticationException 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 im Sinne unseres Beispiels.
5. Mehrere Authentifizierungsanbieter konfigurieren
Fügen wir nun dieCustomAuthenticationProvider 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 mitAuthenticationManagerBuilder hinzu.
Zuerst dieCustomAuthenticationProvider und dann ein speicherinterner Authentifizierungsanbieter unter Verwendung voninMemoryAuthentication().
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 validieren die Anmeldeinformationen und bestimmen, ob der Zugriff gewährt 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 werden:
@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 speicherinternen 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 kann der vollständige Quellcode der Implementierungover on GitHub gefunden werden.