OAuth2.0 et enregistrement client dynamique (à l'aide de la pile héritée Spring Security OAuth)

1. Introduction

Dans ce tutoriel, nous allons préparer un enregistrement client dynamique avec OAuth2.0. OAuth2.0 est une infrastructure d'autorisation qui permet d'obtenir un accès limité aux comptes d'utilisateurs sur un service HTTP. Le client OAuth2.0 est l'application qui souhaite accéder au compte de l'utilisateur. Ce client peut être une application Web externe, un agent utilisateur ou simplement un client natif.

Afin de réaliser une inscription client dynamique, nous allons stocker les informations d'identification dans la base de données, au lieu d'une configuration codée en dur. L'application que nous allons étendre a été initialement décrite dans le didacticiel Spring REST API + OAuth2.

Remarque : cet article utilise le projet hérité Spring OAuth.

2. Dépendances de Maven

Nous allons d'abord configurer l'ensemble de dépendances suivant:

 org.springframework.boot spring-boot-starter-web   org.springframework spring-jdbc   org.springframework.security.oauth spring-security-oauth2 

Notez que nous utilisons spring-jdbc car nous allons utiliser une base de données pour stocker les nouveaux utilisateurs enregistrés avec des mots de passe.

3. Configuration du serveur OAuth2.0

Tout d'abord, nous devons configurer notre serveur d'autorisation OAuth2.0. La configuration principale est dans la classe suivante:

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

Il y a quelques éléments majeurs que nous devons configurer; commençons par ClientDetailsServiceConfigurer:

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

Cela garantira que nous utilisons la persistance pour obtenir les informations client.

Configurons bien sûr cette source de données standard:

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

Et donc, maintenant, notre application utilisera la base de données comme source de clients enregistrés, au lieu des clients généralement codés en dur dans la mémoire.

4. Le schéma DB

Définissons maintenant la structure SQL pour stocker nos clients OAuth:

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

Les champs les plus importants des oauth_client_details sur lesquels nous devrions nous concentrer sont:

  • client_id - pour stocker l'id des clients nouvellement enregistrés
  • client_secret - pour stocker le mot de passe des clients
  • access_token_validity - qui indique si le client est toujours valide
  • autorités - pour indiquer quels rôles sont autorisés avec un client particulier
  • scope - actions autorisées, par exemple écrire des statuts sur Facebook, etc.
  • allowed_grant_types , qui fournit des informations sur la manière dont les utilisateurs peuvent se connecter au client particulier (dans notre exemple, il s'agit d'un formulaire de connexion avec mot de passe)

Veuillez noter que chaque client a une à plusieurs relations avec les utilisateurs, ce qui signifie naturellement que plusieurs utilisateurs peuvent utiliser un seul client .

5. Persistons certains clients

Avec la définition de schéma SQL, nous pouvons enfin créer des données dans le système - et définir essentiellement un client.

Nous allons utiliser le script data.sql suivant - que Spring Boot exécutera par défaut - pour initialiser la base de données:

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

La description des champs les plus importants dans oauth_client_details est fournie dans la section précédente.

6. Test

Afin de tester l'enregistrement dynamique du client, nous devons exécuter les projets spring-security-oauth-server et spring-security-oauth-resource , respectivement sur les ports 8081 et 8082.

Maintenant, nous pouvons enfin écrire quelques tests en direct.

Supposons que nous ayons enregistré un client avec un identifiant nommé fooClientIdPassword , qui a un accès pour lire les foos.

Tout d'abord, nous allons essayer d'obtenir un jeton d'accès du serveur d'authentification, en utilisant un client déjà défini:

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

Et voici la logique d'obtention du jeton d'accès:

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("//localhost:8081/spring-security-oauth-server/oauth/token"); return response.jsonPath().getString("access_token"); }

7. Conclusion

Dans ce didacticiel, nous avons appris à enregistrer dynamiquement un nombre illimité de clients avec le framework OAuth2.0.

L'implémentation complète de ce didacticiel se trouve sur GitHub - il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.

Veuillez noter que pour tester, vous devrez ajouter des clients dans DB et que la configuration .inMemory () ne sera plus valide. Si vous souhaitez utiliser l'ancien. inMemory () config, il y a un deuxième fichier contenant la configuration avec des clients codés en dur.