Neu in Spring Security OAuth2 - Ansprüche überprüfen

Neu in Spring Security OAuth2 - Ansprüche überprüfen

1. Überblick

In diesem kurzen Tutorial arbeiten wir mit einer Spring Security OAuth2-Implementierung und lernen, wie Sie JWT-Ansprüche mit den neuenJwtClaimsSetVerifier überprüfen - eingeführt inSpring Security OAuth 2.2.0.RELEASE.

2. Maven-Konfiguration

Zuerst müssen wir die neueste Version vonspring-security-oauth2 zu unserenpom.xml hinzufügen:


    org.springframework.security.oauth
    spring-security-oauth2
    2.2.0.RELEASE

3. Token Store-Konfiguration

Als nächstes konfigurieren wir unsereTokenStore auf dem Ressourcenserver:

@Bean
public TokenStore tokenStore() {
    return new JwtTokenStore(accessTokenConverter());
}

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("123");
    converter.setJwtClaimsSetVerifier(jwtClaimsSetVerifier());
    return converter;
}

Beachten Sie, wie wir den neuen Verifizierer zu unserenJwtAccessTokenConverterhinzufügen.

Weitere Informationen zum Konfigurieren vonJwtTokenStore finden Sie in der Beschreibung zuusing JWT with Spring Security OAuth.

In den folgenden Abschnitten werden nun verschiedene Arten von Anspruchsprüfern erläutert und erläutert, wie sie zusammenarbeiten.

4. IssuerClaimVerifier

Wir beginnen einfach - indem wir den Anspruch des Emittenten "iss" mitIssuerClaimVerifier überprüfen - wie folgt:

@Bean
public JwtClaimsSetVerifier issuerClaimVerifier() {
    try {
        return new IssuerClaimVerifier(new URL("http://localhost:8081"));
    } catch (MalformedURLException e) {
        throw new RuntimeException(e);
    }
}

In diesem Beispiel haben wir ein einfachesIssuerClaimVerifier hinzugefügt, um unseren Emittenten zu überprüfen. Wenn das JWT-Token einen anderen Wert für die Emittentenausgabe "iss" enthält, wird ein einfachesInvalidTokenException ausgelöst.

Wenn das Token den Issuer-Anspruch enthält, wird natürlich keine Ausnahme geworfen, und das Token wird als gültig betrachtet.

5. Benutzerdefinierter Anspruchsprüfer

Interessant ist hier jedoch, dass wir auch unseren benutzerdefinierten Anspruchsprüfer erstellen können:

@Bean
public JwtClaimsSetVerifier customJwtClaimVerifier() {
    return new CustomClaimVerifier();
}

Hier ist eine einfache Implementierung, wie dies aussehen kann - um zu überprüfen, ob der Anspruch vonuser_namein unserem JWT-Token vorhanden ist:

public class CustomClaimVerifier implements JwtClaimsSetVerifier {
    @Override
    public void verify(Map claims) throws InvalidTokenException {
        String username = (String) claims.get("user_name");
        if ((username == null) || (username.length() == 0)) {
            throw new InvalidTokenException("user_name claim is empty");
        }
    }
}

Beachten Sie, dass wir hier einfach dieJwtClaimsSetVerifier-Schnittstelle implementieren und dann eine vollständig benutzerdefinierte Implementierung für die Überprüfungsmethode bereitstellen. Dies gibt uns volle Flexibilität für jede Art von Überprüfung, die wir benötigen.

6. Kombinieren Sie mehrere Anspruchsprüfer

Lassen Sie uns abschließend sehen, wie Sie mehrere Anspruchsprüfer mitDelegatingJwtClaimsSetVerifier kombinieren - wie folgt:

@Bean
public JwtClaimsSetVerifier jwtClaimsSetVerifier() {
    return new DelegatingJwtClaimsSetVerifier(Arrays.asList(
      issuerClaimVerifier(), customJwtClaimVerifier()));
}

DelegatingJwtClaimsSetVerifier nimmt eine Liste der Objekte vonJwtClaimsSetVerifierund delegiert den Anspruchsüberprüfungsprozess an diese Verifizierer.

7. Einfacher Integrationstest

Nachdem wir mit der Implementierung fertig sind, testen wir unsere Anspruchsprüfer mit einem einfachenintegration test:

@RunWith(SpringRunner.class)
@SpringBootTest(
  classes = ResourceServerApplication.class,
  webEnvironment = WebEnvironment.RANDOM_PORT)
public class JwtClaimsVerifierIntegrationTest {

    @Autowired
    private JwtTokenStore tokenStore;

    ...
}

Wir beginnen mit einem Token, das keinen Aussteller enthält (aberuser_name enthält) - was gültig sein sollte:

@Test
public void whenTokenDontContainIssuer_thenSuccess() {
    String tokenValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);

    assertTrue(auth.isAuthenticated());
}

Der Grund, warum dies gültig ist, ist einfach: Der erste Prüfer ist nur aktiv, wenn ein Ausstelleranspruch im Token vorhanden ist. Wenn dieser Anspruch nicht besteht, wird der Prüfer nicht aktiviert.

Schauen wir uns als nächstes ein Token an, das auch einen gültigen Aussteller (http://localhost:8081) und einenuser_name enthält. Dies sollte auch gültig sein:

@Test
public void whenTokenContainValidIssuer_thenSuccess() {
    String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);

    assertTrue(auth.isAuthenticated());
}

Wenn das Token einen ungültigen Aussteller enthält (http://localhost:8082), wird es überprüft und als ungültig eingestuft:

@Test(expected = InvalidTokenException.class)
public void whenTokenContainInvalidIssuer_thenException() {
    String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);

    assertTrue(auth.isAuthenticated());
}

Wenn das Token keineuser_name-Anforderung enthält, ist es ungültig:

@Test(expected = InvalidTokenException.class)
public void whenTokenDontContainUsername_thenException() {
    String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);

    assertTrue(auth.isAuthenticated());
}

Und schließlich, wenn das Token eine leereuser_name-Anforderung enthält, ist es auch ungültig:

@Test(expected = InvalidTokenException.class)
public void whenTokenContainEmptyUsername_thenException() {
    String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);

    assertTrue(auth.isAuthenticated());
}

8. Fazit

In diesem kurzen Artikel haben wir uns die neuen Überprüfungsfunktionen in Spring Security OAuth angesehen.

Wie immer ist der vollständige Quellcodeover on GitHub verfügbar.