OAuth2.0 und dynamische Client-Registrierung

OAuth2.0 and Dynamic Client Registration

1. Einführung

In diesem Lernprogramm bereiten wir eine dynamische Clientregistrierung mit OAuth2.0 vor. OAuth2.0 ist ein Autorisierungsframework, mit dem der Zugriff auf Benutzerkonten eines HTTP-Dienstes eingeschränkt werden kann. Der OAuth2.0-Client ist die Anwendung, die auf das Benutzerkonto zugreifen möchte. Dieser Client kann eine externe Webanwendung, ein Benutzeragent oder nur ein nativer Client sein.

Um eine dynamische Clientregistrierung zu erreichen, speichern wir die Anmeldeinformationen in der Datenbank anstelle der fest codierten Konfiguration. Die Anwendung, die wir erweitern werden, wurde ursprünglich inSpring REST API + OAuth2 tutorial beschrieben.

2. Maven-Abhängigkeiten

Wir richten zunächst die folgenden Abhängigkeiten ein:


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


    org.springframework
    spring-jdbc


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

Beachten Sie, dass wirspring-jdbc verwenden, da wir eine Datenbank verwenden, um die neu registrierten Benutzer mit Kennwörtern zu speichern.

3. OAuth2.0 Server Configuration

Zuerst müssen wir unseren OAuth2.0-Autorisierungsserver konfigurieren. Die Hauptkonfiguration befindet sich in der folgenden Klasse:

@Configuration
@PropertySource({ "classpath:persistence.properties" })
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig
  extends AuthorizationServerConfigurerAdapter {

    // config
}

Es gibt einige wichtige Dinge, die wir konfigurieren müssen. Beginnen wir mitClientDetailsServiceConfigurer:

@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
    clients.jdbc(dataSource())

    // ...
}

Dadurch wird sichergestellt, dass wir die Persistenz verwenden, um die Kundeninformationen abzurufen.

Lassen Sie uns natürlich diese Standarddatenquelle einrichten:

@Bean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();

    dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
    dataSource.setUrl(env.getProperty("jdbc.url"));
    dataSource.setUsername(env.getProperty("jdbc.user"));
    dataSource.setPassword(env.getProperty("jdbc.pass"));
    return dataSource;
}

Und so wird unsere Anwendung jetzt die Datenbank als Quelle für registrierte Clients verwenden, anstatt die in Speicher-Clients üblichen fest codierten.

4. Das DB-Schema

Definieren wir nun die SQL-Struktur zum Speichern unserer OAuth-Clients:

create table oauth_client_details (
    client_id VARCHAR(256) PRIMARY KEY,
    resource_ids VARCHAR(256),
    client_secret VARCHAR(256),
    scope VARCHAR(256),
    authorized_grant_types VARCHAR(256),
    web_server_redirect_uri VARCHAR(256),
    authorities VARCHAR(256),
    access_token_validity INTEGER,
    refresh_token_validity INTEGER,
    additional_information VARCHAR(4096),
    autoapprove VARCHAR(256)
);

Die wichtigsten Felder aus denoauth_client_details, auf die wir uns konzentrieren sollten, sind:

  • client_id - zum Speichern der ID neu registrierter Clients

  • client_secret - um das Passwort von Clients zu speichern

  • access_token_validity - Zeigt an, ob der Client noch gültig ist

  • authorities - um anzugeben, welche Rollen für einen bestimmten Client zulässig sind

  • scope - erlaubte Aktionen, zum Beispiel das Schreiben von Status auf Facebook usw.

  • authorized_grant_types, das Informationen darüber enthält, wie Benutzer sich bei einem bestimmten Client anmelden können (in unserem Beispiel handelt es sich um eine Formularanmeldung mit Kennwort).

Bitte beachten Sie, dass jeder Client eine bis viele Beziehungen zu Benutzern hat, was natürlich bedeutet, dassmultiple users can utilize a single client.

5. Lassen Sie uns einige Kunden bestehen

Mit der SQL-Schemadefinition können wir endlich einige Daten im System erstellen - und im Grunde genommen einen Client definieren.

Wir werden das folgendedata.sql-Skript verwenden, das Spring Boot standardmäßig ausführt, um die Datenbank zu initialisieren:

INSERT INTO oauth_client_details
    (client_id, client_secret, scope, authorized_grant_types,
    web_server_redirect_uri, authorities, access_token_validity,
    refresh_token_validity, additional_information, autoapprove)
VALUES
    ("fooClientIdPassword", "secret", "foo,read,write,
    "password,authorization_code,refresh_token", null, null, 36000, 36000, null, true);

Die Beschreibung der wichtigsten Felder inoauth_client_details finden Sie im vorherigen Abschnitt.

6. Testen

Um die dynamische Clientregistrierung zu testen, müssen sowohlspring-security-oauth-server- als auchspring-security-oauth-resource-Projekte auf den 8081- bzw. 8082-Ports ausgeführt werden.

Jetzt können wir endlich ein paar Live-Tests schreiben.

Nehmen wir an, wir haben einen Client mit der IDfooClientIdPassword registriert, der Zugriff auf Lesefolien hat.

Zunächst versuchen wir, mithilfe eines bereits definierten Clients ein Zugriffstoken vom Auth-Server abzurufen:

@Test
public void givenDBUser_whenRevokeToken_thenAuthorized() {
    String accessToken = obtainAccessToken("fooClientIdPassword", "john", "123");

    assertNotNull(accessToken);
}

Und hier ist die Logik zum Erhalten des Zugriffstokens:

private String obtainAccessToken(String clientId, String username, String password) {
    Map params = new HashMap();
    params.put("grant_type", "password");
    params.put("client_id", clientId);
    params.put("username", username);
    params.put("password", password);
    Response response = RestAssured.given().auth().preemptive()
      .basic(clientId, "secret").and().with().params(params).when()
      .post("http://localhost:8081/spring-security-oauth-server/oauth/token");
    return response.jsonPath().getString("access_token");
}

7. Fazit

In diesem Tutorial haben wir gelernt, wie eine unbegrenzte Anzahl von Clients mit dem OAuth2.0-Framework dynamisch registriert werden kann.

Die vollständige Implementierung dieses Tutorials finden Sie unterover on GitHub - dies ist ein Maven-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein.

Bitte beachten Sie, dass Sie zum Testen Clients zur Datenbank hinzufügen müssen und dass die Konfiguration von.inMemory()nicht mehr gültig ist. Wenn Sie die alte Konfiguration von.inMemory()verwenden möchten, gibt es eine zweite Datei, die die Konfiguration mit fest codierten Clients enthält.