Mehrere Authentifizierungsanbieter in Spring Security

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.