Creazione di un microservizio JHipster di base protetto da UAA

1. Panoramica

Negli articoli precedenti, abbiamo trattato le basi di JHipster e come usarlo per generare un'applicazione basata su microservizi.

In questo tutorial, esploreremo l'account utente e il servizio di autorizzazione di JHipster, in breve UAA, e come utilizzarlo per proteggere un'applicazione di microservizi basata su JHispter a tutti gli effetti. Ancora meglio, tutto questo può essere ottenuto senza scrivere una sola riga di codice !

2. Caratteristiche principali della UAA

Una caratteristica importante delle applicazioni che abbiamo creato nei nostri articoli precedenti è che gli account utente ne erano parte integrante. Ora, questo va bene quando abbiamo una singola applicazione, ma cosa succede se vogliamo condividere gli account utente tra più applicazioni generate da JHipster? È qui che entra in gioco la UAA di JHipster.

La UAA di JHipster è un microservizio creato, distribuito ed eseguito indipendentemente dagli altri servizi nella nostra applicazione . Serve come:

  • Un server di autorizzazione OAuth2, basato sull'implementazione di Spring Boot
  • Un Identity Management Server, che espone l'API CRUD di un account utente

JHipster UAA supporta anche le tipiche funzioni di accesso come l'autoregistrazione e "ricordami". E, naturalmente, si integra completamente con altri servizi JHipster.

3. Configurazione dell'ambiente di sviluppo

Prima di iniziare qualsiasi sviluppo, dobbiamo prima essere sicuri che il nostro ambiente abbia tutti i suoi prerequisiti impostati. Oltre a tutti gli strumenti descritti nel nostro articolo Introduzione a JHipster, avremo bisogno di un registro JHipster in esecuzione. Proprio come un breve riepilogo, il servizio di registro consente ai diversi servizi che creeremo di trovarsi e dialogare tra loro.

La procedura completa per la generazione e l'esecuzione del registro è descritta nella sezione 4.1 del nostro articolo JHipster con un'architettura di microservizi, quindi non la ripeteremo qui. È disponibile anche un'immagine Docker che può essere utilizzata come alternativa.

4. Generazione di un nuovo servizio JHipster UAA

Generiamo il nostro servizio UAA utilizzando l'utilità della riga di comando JHipster:

$ mkdir uaa $ cd uaa $ jhipster 

La prima domanda a cui dobbiamo rispondere è quale tipo di applicazione vogliamo generare. Utilizzando i tasti freccia, selezioneremo l'opzione "JHipster UAA (for microservice OAuth2 authentication)":

Successivamente, ci verranno richieste alcune domande riguardanti dettagli specifici riguardanti il ​​servizio generato, come il nome dell'applicazione, la porta del server e il rilevamento del servizio:

Per la maggior parte, le risposte predefinite vanno bene. Per quanto riguarda il nome di base dell'applicazione, che influenza molti degli artefatti generati , abbiamo scelto "uaa" (minuscolo) - un nome sensato. Possiamo giocare con gli altri valori se vogliamo, ma non cambierà le caratteristiche principali del progetto generato.

Dopo aver risposto a queste domande, JHipster creerà tutti i file di progetto e installerà le dipendenze dei pacchetti npm (che in questo caso non sono realmente utilizzate).

Ora possiamo utilizzare lo script Maven locale per creare ed eseguire il nostro servizio 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! ---------------------------------------------------------- 

Il messaggio chiave a cui prestare attenzione qui è quello che afferma che UAA è collegata al registro JHipster. Questo messaggio indica che UAA è riuscita a registrarsi e sarà disponibile per il rilevamento da parte di altri microservizi e gateway.

5. Test del servizio UAA

Poiché il servizio UAA generato non ha un'interfaccia utente da solo, è necessario utilizzare chiamate API dirette per verificare se funziona come previsto.

Ci sono due funzionalità che dobbiamo assicurarci che funzionino prima di utilizzarlo con altre parti o il nostro sistema: la generazione di token OAuth2 e il recupero dell'account.

Innanzitutto, otteniamo un nuovo token dall'endpoint OAuth della nostra UAA , utilizzando un semplice comando curl :

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

Qui, abbiamo utilizzato il flusso di concessione della password , utilizzando due coppie di credenziali. In questo tipo di flusso, inviamo le credenziali del client utilizzando l'autenticazione HTTP di base, che codifichiamo direttamente nell'URL.

Le credenziali dell'utente finale vengono inviate come parte del corpo, utilizzando i parametri nome utente e password standard. Stiamo anche utilizzando l'account utente denominato "utente" , disponibile per impostazione predefinita nel profilo di prova.

Supponendo di aver fornito tutti i dettagli correttamente, otterremo una risposta contenente un token di accesso e un token di aggiornamento:

{ "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" }

Ora possiamo utilizzare access_token restituito per ottenere informazioni per l'account associato utilizzando la risorsa account , disponibile nel servizio 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" ] } 

Tieni presente che dobbiamo emettere questo comando prima che il token di accesso scada . Per impostazione predefinita, il servizio UAA emette token validi per cinque minuti, che è un valore ragionevole per la produzione.

Possiamo facilmente cambiare la durata dei token validi modificando il file application-.yml corrispondente al profilo con cui stiamo eseguendo l'app e impostando la chiave uaa.web-client-configuration.access-token-validity-in-seconds . I file delle impostazioni risiedono nella directory src / main / resources / config del nostro progetto UAA.

6. Generazione del gateway abilitato per UAA

Ora che siamo sicuri che il nostro servizio UAA e il registro dei servizi funzionino, creiamo un ecosistema con cui interagire. Alla fine avremo aggiunto:

  • Un front-end basato su Angular
  • Un back-end di microservizi
  • Un gateway API che fronteggia entrambi

Cominciamo effettivamente con il gateway, poiché sarà il servizio che negozierà con UAA per l'autenticazione. Ospiterà la nostra applicazione front-end e instraderà le richieste API ad altri microservizi.

Ancora una volta, useremo lo strumento da riga di comando JHipster all'interno di una directory appena creata:

$ mkdir gateway $ cd gateway $ jhipster

Come prima, dobbiamo rispondere ad alcune domande per generare il progetto. Quelle importanti sono le seguenti:

  • Tipo di applicazione : deve essere "Microservices gateway"
  • 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)

Anche con queste osservazioni, l'utilizzo di uno strumento come JHispter può aiutare molto nello sviluppo di una nuova applicazione. Porterà con sé una solida base e potrà mantenere un buon livello di coerenza nella nostra base di codice man mano che il sistema e gli sviluppatori si evolvono.

9. Conclusione

In questo articolo, abbiamo mostrato come utilizzare JHispter per creare un'applicazione funzionante basata su un'architettura di microservizi e sul server UAA di JHipster. Ci siamo riusciti senza scrivere una sola riga di codice Java , il che è piuttosto impressionante.

Come al solito, il codice completo per i progetti presentati in questo articolo è disponibile nel nostro repository GitHub.