Création d'un microservice JHipster de base sécurisé UAA

1. Vue d'ensemble

Dans les articles précédents, nous avons couvert les bases de JHipster et comment l'utiliser pour générer une application basée sur des microservices.

Dans ce didacticiel, nous explorerons le service de compte d'utilisateur et d'autorisation de JHipster - UAA en abrégé - et comment l'utiliser pour sécuriser une application de microservice à part entière basée sur JHispter. Mieux encore, tout cela peut être réalisé sans écrire une seule ligne de code !

2. Fonctionnalités de base de UAA

Une caractéristique importante des applications que nous avons créées dans nos articles précédents est que les comptes d'utilisateurs en faisaient partie intégrante. Maintenant, c'est bien lorsque nous avons une seule application, mais que faire si nous voulons partager des comptes d'utilisateurs entre plusieurs applications générées par JHipster? C'est là qu'intervient l'UAA de JHipster.

L'AUA de JHipster est un microservice qui est construit, déployé et exécuté indépendamment des autres services de notre application . Il sert de:

  • Un serveur d'autorisation OAuth2, basé sur l'implémentation de Spring Boot
  • Un serveur de gestion d'identité, exposant une API CRUD de compte d'utilisateur

JHipster UAA prend également en charge les fonctionnalités de connexion typiques telles que l'auto-enregistrement et «Remember me». Et bien sûr, il s'intègre pleinement avec les autres services JHipster.

3. Configuration de l'environnement de développement

Avant de commencer tout développement, nous devons d'abord nous assurer que notre environnement a tous ses prérequis mis en place. Outre tous les outils décrits dans notre article Intro To JHipster, nous aurons besoin d'un registre JHipster en cours d'exécution. Pour récapituler rapidement, le service de registre permet aux différents services que nous allons créer de se trouver et de se parler.

La procédure complète pour générer et exécuter le registre est décrite dans la section 4.1 de notre JHipster avec un article sur l'architecture de microservice, nous ne la répéterons donc pas ici. Une image Docker est également disponible et peut être utilisée comme alternative.

4. Génération d'un nouveau service JHipster UAA

Générons notre service UAA à l'aide de l'utilitaire de ligne de commande JHipster:

$ mkdir uaa $ cd uaa $ jhipster 

La première question à laquelle nous devons répondre est de savoir quel type d'application nous voulons générer. À l'aide des touches fléchées, nous sélectionnerons l'option "JHipster UAA (pour l'authentification du microservice OAuth2)":

Ensuite, nous serons invités à poser quelques questions concernant des détails spécifiques concernant le service généré, tels que le nom de l'application, le port du serveur et la découverte de service:

Pour la plupart, les réponses par défaut sont correctes. En ce qui concerne le nom de base de l'application, qui affecte de nombreux artefacts générés , nous avons choisi «uaa» (minuscule) - un nom raisonnable. Nous pouvons jouer avec les autres valeurs si nous le voulons, mais cela ne changera pas les principales caractéristiques du projet généré.

Après avoir répondu à ces questions, JHipster créera tous les fichiers de projet et installera les dépendances du package npm (qui ne sont pas vraiment utilisées dans ce cas).

Nous pouvons maintenant utiliser le script Maven local pour créer et exécuter notre service UAA:

$ ./mvnw ... build messages omitted 2018-10-14 14:07:17.995 INFO 18052 --- [ restartedMain] com.baeldung.jhipster.uaa.UaaApp : ---------------------------------------------------------- Application 'uaa' is running! Access URLs: Local: //localhost:9999/ External: //192.168.99.1:9999/ Profile(s): [dev, swagger] ---------------------------------------------------------- 2018-10-14 14:07:18.000 INFO 18052 --- [ restartedMain] com.baeldung.jhipster.uaa.UaaApp : ---------------------------------------------------------- Config Server: Connected to the JHipster Registry config server! ---------------------------------------------------------- 

Le message clé auquel il faut prêter attention ici est celui indiquant que UAA est connecté au registre JHipster. Ce message indique que UAA a pu s'enregistrer et sera disponible pour la découverte par d'autres microservices et passerelles.

5. Test du service UAA

Étant donné que le service UAA généré n'a pas d'interface utilisateur en lui-même, nous devons utiliser des appels d'API directs pour tester s'il fonctionne comme prévu.

Il y a deux fonctionnalités dont nous devons nous assurer qu'elles fonctionnent avant de l'utiliser avec d'autres parties ou notre système: la génération de jetons OAuth2 et la récupération de compte.

Tout d'abord, récupérons un nouveau jeton du point de terminaison OAuth de notre UAA , en utilisant une simple commande curl :

$ curl -X POST --data \ "username=user&password=user&grant_type=password&scope=openid" \ //web_app:[email protected]:9999/oauth/token 

Ici, nous avons utilisé le flux d' octroi de mot de passe , en utilisant deux paires d'informations d'identification. Dans ce type de flux, nous envoyons les informations d'identification du client en utilisant l'authentification HTTP de base, que nous encodons directement dans l'URL.

Les informations d'identification de l'utilisateur final sont envoyées dans le corps, en utilisant les paramètres standard de nom d'utilisateur et de mot de passe. Nous utilisons également le compte utilisateur nommé «utilisateur» , qui est disponible par défaut dans le profil de test.

En supposant que nous ayons fourni tous les détails correctement, nous obtiendrons une réponse contenant un jeton d'accès et un jeton d'actualisation:

{ "access_token" : "eyJh...(token omitted)", "token_type" : "bearer", "refresh_token" : "eyJ...(token omitted)", "expires_in" : 299, "scope" : "openid", "iat" : 1539650162, "jti" : "8066ab12-6e5e-4330-82d5-f51df16cd70f" }

Nous pouvons maintenant utiliser le access_token retourné pour obtenir des informations sur le compte associé à l'aide de la ressource de compte , qui est disponible dans le service UAA:

$ curl -H "Authorization: Bearer eyJh...(access token omitted)" \ //localhost:9999/api/account { "id" : 4, "login" : "user", "firstName" : "User", "lastName" : "User", "email" : "[email protected]", "imageUrl" : "", "activated" : true, "langKey" : "en", "createdBy" : "system", "createdDate" : "2018-10-14T17:07:01.336Z", "lastModifiedBy" : "system", "lastModifiedDate" : null, "authorities" : [ "ROLE_USER" ] } 

Veuillez noter que nous devons émettre cette commande avant l'expiration du jeton d'accès . Par défaut, le service UAA émet des jetons valides pendant cinq minutes, ce qui est une valeur raisonnable pour la production.

Nous pouvons facilement modifier la durée de vie des jetons valides en modifiant le fichier application-.yml correspondant au profil sous lequel nous exécutons l'application et en définissant la clé uaa.web-client-configuration.access-token-validité-en-secondes . Les fichiers de paramètres résident dans le répertoire src / main / resources / config de notre projet UAA.

6. Génération de la passerelle compatible UAA

Maintenant que nous sommes convaincus que notre service UAA et notre registre de services fonctionnent, créons un écosystème avec lequel ils pourront interagir. À la fin, nous aurons ajouté:

  • Un frontal basé sur Angular
  • Un back-end de microservice
  • Une passerelle API qui fait face à ces deux

Commençons en fait par la passerelle, car ce sera le service qui négociera avec UAA pour l'authentification. Il va héberger notre application frontale et acheminer les demandes d'API vers d'autres microservices.

Encore une fois, nous utiliserons l'outil de ligne de commande JHipster dans un répertoire nouvellement créé:

$ mkdir gateway $ cd gateway $ jhipster

Comme auparavant, nous devons répondre à quelques questions afin de générer le projet. Les plus importants sont les suivants:

  • Type d'application : doit être «passerelle microservices»
  • Application name: We'll use “gateway” this time
  • Service discovery: Select “JHipster registry”
  • Authentication type:We must select the “Authentication with JHipster UAA server” option here
  • UI Framework: Let's pick “Angular 6”

Once JHipster generates all its artifacts, we can build and run the gateway with the provided Maven wrapper script:

$ ./mwnw ... many messages omitted ---------------------------------------------------------- Application 'gateway' is running! Access URLs: Local: //localhost:8080/ External: //192.168.99.1:8080/ Profile(s): [dev, swagger] ---------------------------------------------------------- 2018-10-15 23:46:43.011 INFO 21668 --- [ restartedMain] c.baeldung.jhipster.gateway.GatewayApp : ---------------------------------------------------------- Config Server: Connected to the JHipster Registry config server! ---------------------------------------------------------- 

With the above message, we can access our application by pointing our browser to //localhost:8080, which should display the default generated homepage:

Let's go ahead and log into our application, by navigating to the Account > Login menu item. We'll use admin/admin as credentials, which JHipster creates automatically by default. All going well, the welcome page will display a message confirming a successful logon:

Let's recap what happened to get us here: First, the gateway sent our credentials to UAA's OAuth2 token endpoint, which validated them and generated a response containing an access and a refresh JWT token. The gateway then took those tokens and sent them back to the browser as cookies.

Next, the Angular front-end called the /uaa/api/account API, which once again the gateway forwarded to UAA. In this process, the gateway takes the cookie containing the access token and use its value to add an authorization header to the request.

If needed, we can see all this flow in great detail by checking both UAA and Gateway's logs. We can also get full wire-level data by setting the org.apache.http.wire logger level to DEBUG.

7. Generating a UAA-Enabled Microservice

Now that our application environment is up and running, it's time to add a simple microservice to it. We'll create a “quotes” microservice, which will expose a full REST API that allows us to create, query, modify, and delete a set of stock quotes. Each quote will have only three properties:

  • The quote's trade symbol
  • Its price, and
  • The last trade's timestamp

Let's go back to our terminal and use JHipster's command-line tool to generate our project:

$ mkdir quotes $ cd quotes $ jhipster 

This time, we'll ask JHipster to generate a Microservice application, which we'll call “quotes”. The questions are similar to the ones we've answered before. We can keep the defaults for most of them, except for these three:

  • Service Discovery: Select “JHipster Registry” since we're already using it in our architecture
  • Path to the UAA application: Since we're keeping all projects directories under the same folder, this will be ../uaa (unless we've changed it, of course)
  • Authentication Type: Select “JHipster UAA server”

Here's what a typical sequence of answers will look like in our case:

Once JHipster finishes generating the project, we can go ahead and build it:

$ mvnw ... many, many messages omitted ---------------------------------------------------------- Application 'quotes' is running! Access URLs: Local: //localhost:8081/ External: //192.168.99.1:8081/ Profile(s): [dev, swagger] ---------------------------------------------------------- 2018-10-19 00:16:05.581 INFO 16092 --- [ restartedMain] com.baeldung.jhipster.quotes.QuotesApp : ---------------------------------------------------------- Config Server: Connected to the JHipster Registry config server! ---------------------------------------------------------- ... more messages omitted 

The message “Connected to the JHipster Registry config server!” is what we're looking for here. Its presence tells us that the microservice registered itself with the registry and, because of this, the gateway will be able to route requests to our “quotes” resource and display it on a nice UI, once we've created it. Since we're using a microservice architecture, we split this task into two parts:

  • Create the “quotes” resource back-end service
  • Create the “quotes” UI in the front-end (part of the gateway project)

7.1. Adding the Quotes Resource

First, we need to make sure the that the quotes microservice application is stopped — we can hit CTRL-C on the same console window that we previously used to run it.

Now, let's add an entity to the project using JHipster's tool. This time we'll use the import-jdl command, which will save us from the tedious and error-prone process of supplying all details individually. For additional information about the JDL format, please refer to the full JDL reference.

Next, we create a text file called quotes.jh containing our Quote entity definition, along with some code generation directives:

entity Quote { symbol String required unique, price BigDecimal required, lastTrade ZonedDateTime required } dto Quote with mapstruct paginate Quote with pagination service Quote with serviceImpl microservice Quote with quotes filter Quote clientRootFolder Quote with quotes 

We can now import this entity definition to our project:

$ jhipster import-jdl quotes.jh 

Note: during the import, JHipster will complain about a conflict while applying changes to the master.xml file. We can safely choose the overwrite option in this case.

We can now build and run our microservice again using mvnw. Once it's up, we can verify that the gateway picks up the new route accessing the Gateway view, available from the Administration menu. This time, we can see that there's an entry for the “/quotes/**” route, whichshows that the backend is ready to be used by the UI.

7.2. Adding the Quotes UI

Finally, let's generate the CRUD UI in the gateway project that we'll use to access our quotes. We'll use the same JDL file from the “quotes” microservice project to generate the UI components, and we'll import it using JHipster's import-jdl command:

$ jhipster import-jdl ../jhipster-quotes/quotes.jh ...messages omitted ? Overwrite webpack\webpack.dev.js? y ... messages omitted Congratulations, JHipster execution is complete! 

During the import, JHipster will prompt a few times for the action it should take regarding conflicting files. In our case, we can simply overwrite existing resources, since we haven't done any customization.

Now we can restart the gateway and see what we've accomplished. Let's point our browser to the gateway at //localhost:8080, making sure we refresh its contents. The Entities menu should now have a new entry for the Quotes resource:

Clicking on this menu option brings up the Quotes listing screen:

As expected, the listing is empty — we haven't added any quotes yet! Let's try to add one by clicking the “Create New Quote Button” on the top right of this screen, which brings us to the create/edit form:

We can see that the generated form has all expected features:

  • Required fields are marked with a red indicator, which turns green once filled
  • Date/Time and numeric fields use native components to help with data entry
  • We can cancel this activity, which will leave data unchanged, or save our new or modified entity

After filling this form and hitting Save, we'll see the results on the listing screen. We can now see the new Quotes instancein the data grid:

As an admin, we also have access to the API menu item, which takes us to the standard Swagger API Developer Portal. In this screen, we can select one of the available APIs to exercise:

  • default: Gateway's own API that displays available routes
  • uaa: Account and User APIs
  • quotes: Quotes API

8. Next Steps

The application we've built so far works as expected and provides a solid base for further development. We'll most definitely also need to write some (or a lot of) custom code, depending on the complexity of our requirements. Some areas that are likely to need some work are:

  • UI look and feel customization: This is usually quite easy due to the way the front-end application is structured — we can go a long way simply by fiddling with CSS and adding some images
  • User repository changes: Some organizations already have some sort of internal user repository (e.g. an LDAP directory) — this will require changes on the UAA, but the nice part is that we only need to change it once
  • Finer grained authorization on entities:The standard security model used by the generated entity back-end does not have any kind of instance-level and/or field-level security — it's up to the developer to add those restrictions at the appropriate level (API or service, depending on the case)

Même avec ces remarques, l'utilisation d'un outil comme JHispter peut beaucoup aider lors du développement d'une nouvelle application. Il apportera une base solide et pourra maintenir un bon niveau de cohérence dans notre base de code à mesure que le système - et les développeurs - évoluent.

9. Conclusion

Dans cet article, nous avons montré comment utiliser JHispter pour créer une application fonctionnelle basée sur une architecture de microservices et le serveur UAA de JHipster. Nous y sommes parvenus sans écrire une seule ligne de code Java , ce qui est assez impressionnant.

Comme d'habitude, le code complet des projets présentés dans cet article est disponible dans notre référentiel GitHub.