Изграждане на основна защитена с UAA микрослужба JHipster

1. Общ преглед

В предишни статии разгледахме основите на JHipster и как да го използваме за генериране на базирано на микроуслуги приложение.

В този урок ще проучим услугата за потребителски акаунт и упълномощаване на JHipster - накратко UAA - и как да я използваме за осигуряване на пълноценно JHispter-базирано приложение за микросервиз. Още по-добре, всичко това може да се постигне, без да се пише нито един ред код !

2. Основни характеристики на ИЗП

Важна характеристика на приложенията, които сме изградили в предишните ни статии, е, че потребителските акаунти са били неразделна част от тях. Сега това е добре, когато имаме едно приложение, но какво, ако искаме да споделяме потребителски акаунти между множество приложения, генерирани от JHipster? Тук идва UAA на JHipster.

UAA на JHipster е микроуслуга, която е изградена, внедрена и работи независимо от другите услуги в нашето приложение . Той служи като:

  • OAuth2 сървър за оторизация, базиран на внедряването на Spring Boot
  • Сървър за управление на идентичност, излагащ CRUD API на потребителски акаунт

JHipster UAA също поддържа типични функции за вход като саморегистриране и „помни ме“. И разбира се, той се интегрира напълно с други услуги на JHipster.

3. Настройка на среда за разработка

Преди да започнем каквото и да е развитие, първо трябва да сме сигурни, че нашата среда има всички необходими условия. Освен всички инструменти, описани в нашата статия за въвеждане в JHipster, ще ни е необходим работещ регистър на JHipster. Точно като бързо обобщение, услугата за регистрация позволява на различните услуги, които ще създадем, да се намират и да говорят помежду си.

Пълната процедура за генериране и стартиране на системния регистър е описана в раздел 4.1 на нашия JHipster със статия за Microservice Architecture, така че няма да го повтаряме тук. Предлага се и изображение на Docker, което може да се използва като алтернатива.

4. Генериране на нова услуга на JHipster UAA

Нека генерираме нашата услуга UAA с помощта на помощната програма на командния ред JHipster:

$ mkdir uaa $ cd uaa $ jhipster 

Първият въпрос, на който трябва да отговорим, е кой тип приложение искаме да генерираме. Използвайки клавишите със стрелки, ще изберем опцията „JHipster UAA (за микросервизно OAuth2 удостоверяване)“:

След това ще бъдем подканени за няколко въпроса относно конкретни подробности относно генерираната услуга, като име на приложение, порт на сървъра и откриване на услугата:

В по-голямата си част отговорите по подразбиране са добре. Що се отнася до основното име на приложението, което засяга много от генерираните артефакти , ние избрахме „uaa“ (с малки букви) - разумно име. Можем да си поиграем с другите стойности, ако искаме, но това няма да промени основните характеристики на генерирания проект.

След като отговори на тези въпроси, JHipster ще създаде всички файлове на проекта и ще инсталира зависимости на пакета npm (които всъщност не се използват в този случай).

Вече можем да използваме локалния скрипт Maven за изграждане и стартиране на нашата услуга 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! ---------------------------------------------------------- 

Основното съобщение, на което трябва да обърнете внимание тук, е, че UAA е свързано с регистъра на JHipster. Това съобщение показва, че UAA е успяла да се регистрира и ще бъде достъпна за откриване от други микроуслуги и шлюзове.

5. Тестване на услугата UAA

Тъй като генерираната услуга UAA сама по себе си няма потребителски интерфейс, трябва да използваме директни API извиквания, за да тестваме дали тя работи според очакванията.

Има две функционалности, за които трябва да се уверим, че работят, преди да ги използваме с други части или нашата система: OAuth2 генериране на токен и извличане на акаунт.

Първо, нека вземем нов жетон от крайната точка на OAuth на нашия UAA , използвайки проста команда curl :

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

Тук използвахме потока за предоставяне на парола , използвайки две двойки идентификационни данни. В този вид поток ние изпращаме идентификационни данни на клиента, използвайки основно HTTP удостоверяване, което кодираме директно в URL адреса.

Идентификационните данни на крайния потребител се изпращат като част от тялото, като се използват стандартните параметри за потребителско име и парола. Също така използваме потребителския акаунт с име „потребител“ , който е наличен по подразбиране в тестовия профил.

Ако приемем, че сме предоставили всички подробности правилно, ще получим отговор, съдържащ маркер за достъп и маркер за опресняване:

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

Вече можем да използваме върнатия access_token, за да получим информация за свързания акаунт, използвайки ресурса на акаунта , който се предлага в услугата 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" ] } 

Моля, обърнете внимание, че трябва да издадем тази команда преди изтичането на маркера за достъп . По подразбиране услугата UAA издава токени, валидни за пет минути, което е разумна стойност за производството.

Можем лесно да променим продължителността на живота на валидни токени, като редактираме файла application-.yml, съответстващ на профила, под който изпълняваме приложението, и зададем ключа uaa.web-client-configuration.access-token-validity-in-seconds . Файловете с настройки се намират в директорията src / main / resources / config на нашия UAA проект.

6. Generating the UAA-Enabled Gateway

Now that we're confident our UAA service and service registry are working, let's create an ecosystem for these to interact with. By the end, we'll have added:

  • An Angular-based front-end
  • A microservice back-end
  • An API Gateway that fronts both of these

Let's actually begin with the gateway, as it will be the service that will negotiate with UAA for authentication. It's going to host our front-end application and route API requests to other microservices.

Once again, we'll use the JHipster command-line tool inside a newly created directory:

$ mkdir gateway $ cd gateway $ jhipster

As before, we have to answer a few questions in order to generate the project. The important ones are the following:

  • Application type: must be “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)

Дори и с тези забележки, използването на инструмент като JHispter може да помогне много при разработването на ново приложение. Това ще донесе със себе си солидна основа и може да запази добро ниво на последователност в нашата кодова база, тъй като системата - и разработчиците - се развиват.

9. Заключение

В тази статия показахме как да използваме JHispter за създаване на работещо приложение, базирано на архитектура на микроуслуги и UAA сървър на JHipster. Постигнахме това, без да напишем нито един ред Java код , което е доста впечатляващо.

Както обикновено, пълният код за проектите, представени в тази статия, е достъпен в нашето хранилище на GitHub.