Кратко ръководство за използване на Keycloak с Spring Boot

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

В тази статия ще разгледаме основите на настройката на сървър Keycloak, как да свържете приложение Spring Spring към него и как да го използвате с Spring Security .

2. Какво е Keycloak?

Keycloak е решение за управление на идентичността и достъпа с отворен код, насочено към съвременни приложения и услуги.

Keycloak предлага функции като Single-Sign-On (SSO), брокерство за самоличност и социално влизане, потребителска федерация, клиентски адаптери, администраторска конзола и конзола за управление на акаунти. За да научите повече за Keycloak, моля, посетете официалната страница.

В нашия урок ще използваме Admin Console на Keycloak за настройка и след това свързване към Spring Boot с помощта на Keycloak Client Adapter.

3. Настройване на Keycloak сървър

3.1. Изтегляне и инсталиране на Keycloak

Има няколко дистрибуции, от които можете да избирате.

В този урок обаче ще използваме самостоятелната версия.

Нека изтеглим Keycloak-11.0.2 Самостоятелно сървърно разпространение от официалния източник.

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

unzip keycloak-11.0.2.zip cd keycloak-11.0.2/bin ./standalone.sh -Djboss.socket.binding.port-offset=100

След като стартира ./standalone.sh , Keycloak ще стартира своите услуги. След като видим стартиран ред, съдържащ Keycloak 11.0.2 (WildFly Core 12.0.3.Final) , ще знаем, че стартирането му е завършено.

Сега нека отворим браузър и посетим // localhost: 8180. Ще бъдем пренасочени към // localhost: 8180 / auth, за да създадем административен вход:

Нека създадем първоначален администраторски потребител на име Initial1 с паролата zaq1! QAZ . При щракване върху Създаване ще видим съобщение Създадено от потребителя .

Вече можем да преминем към Административната конзола. На страницата за вход ще въведем първоначалните идентификационни данни на администратор:

3.2. Създаване на царство

Един успешен вход ще ни отведе към конзолата и да се отворят по подразбиране на Учителя царството за нас.

Тук ще се съсредоточим върху създаването на персонализирано царство.

Навигиране Нека към горния ляв горен ъгъл да открие Add сфера бутона :

На следващия екран нека добавим ново царство, наречено SpringBootKeycloak :

След като щракнете върху бутона Създаване , ще бъде създадено ново царство и ние ще бъдем пренасочени към него. Всички операции в следващите раздели ще бъдат извършени в това ново царство SpringBootKeycloak .

3.3. Създаване на клиент

Сега ще преминем към страницата за клиенти. Както виждаме на изображението по-долу, Keycloak се предлага с клиенти, които вече са вградени :

Но трябва да добавим нов клиент към нашето приложение, така че ще щракнем Създай . Ще извикаме новото приложение за вход за клиент :

В следващия екран, за този урок, ще оставим всички настройки по подразбиране с изключение на полето Valid Redirect URIs . Това поле трябва да съдържа URL адресите на приложението, които ще използват този клиент за удостоверяване :

По-късно ще създадем Spring Boot Application, работещо на порт 8081, което ще използва този клиент. Следователно използвахме URL за пренасочване на // localhost: 8081 / * по-горе.

3.4. Създаване на роля и потребител

Keycloak използва Role-Based Access. Следователно всеки потребител трябва да има роля.

За да направите това, трябва да отидете на страницата " Роли ":

След това ще добавим потребителската роля:

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

Ще добавим потребител с име user1:

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

Вече можем да отидем в раздела Удостоверения . Ще зададем първоначалната парола на [имейл защитен] :

И накрая, ще преминем към раздела Ролеви съпоставяния . Ще присвоим потребителска роля на нашия user1 :

4. Генериране на токени за достъп с API на Keycloak

Keycloak предоставя REST API за генериране и опресняване на маркери за достъп. Ние можем лесно да използваме този API, за да създадем наша собствена страница за вход.

First, we need to acquire an access token from Keycloak by sending a POST request to this URL:

//localhost:8180/auth/realms/master/protocol/openid-connect/token

The request should have this JSON body:

{     'client_id': 'your_client_id', 'username': 'your_username', 'password': 'your_password', 'grant_type': 'password' }

In response, we'll get an access_token and a refresh_token.

The access token should be used in every request to a Keycloak-protected resource by simply placing it in the Authorization header:

headers: {     'Authorization': 'Bearer' + access_token }

Once the access token has expired, we can refresh it by sending a POST request to the same URL as above, but containing the refresh token instead of username and password:

{     'client_id': 'your_client_id', 'refresh_token': refresh_token_from_previous_request, 'grant_type': 'refresh_token' }

Keycloak will respond to this with a new access_token and refresh_token.

5. Creating a Spring Boot Application

5.1. Dependencies

The latest Spring Boot Keycloak Starter dependencies can be found on Maven Central.

The Keycloak Spring Boot adaptercapitalizes on Spring Boot’s auto-configuration, so all we need to do is add the Keycloak Spring Boot starter to our project.

Within the dependencies XML element, we need the following to run Keycloak with Spring Boot:

 org.keycloak keycloak-spring-boot-starter  

After the dependencies XML element, we need to specify dependencyManagement for Keycloak:

   org.keycloak.bom keycloak-adapter-bom 11.0.2 pom import   

The following embedded containers are supported now and don't require any extra dependencies if using Spring Boot Keycloak Starter:

  • Tomcat
  • Undertow
  • Jetty

5.2. Thymeleaf Web Pages

We're using Thymeleaf for our web pages.

We've got three pages:

  • external.html – an externally facing web page for the public
  • customers.html – an internally facing page that will have its access restricted to only authenticated users with the role user.
  • layout.html – a simple layout, consisting of two fragments, that is used for both the externally facing page and the internally facing page

The code for the Thymeleaf templates is available on Github.

5.3. Controller

The web controller maps the internal and external URLs to the appropriate Thymeleaf templates:

@GetMapping(path = "/") public String index() { return "external"; } @GetMapping(path = "/customers") public String customers(Principal principal, Model model) { addCustomers(); model.addAttribute("customers", customerDAO.findAll()); model.addAttribute("username", principal.getName()); return "customers"; }

For the path /customers, we're retrieving all customers from a repository and adding the result as an attribute to the Model. Later on, we iterate through the results in Thymeleaf.

To be able to display a username, we're injecting the Principal as well.

Note that we're using customer here just as raw data to display, and nothing more.

5.4. Keycloak Configuration

Here's the basic, mandatory configuration:

keycloak.auth-server-url=//localhost:8180/auth keycloak.realm=SpringBootKeycloak keycloak.resource=login-app keycloak.public-client=true 

As we recall, we started Keycloak on port 8180, hence the path specified in keycloak.auth-server-url. We enter the realm name we created in the Keycloak admin console.

The value we specify in keycloak.resource matches the client we named in the admin console.

Here are the security constraints we'll be using:

keycloak.security-constraints[0].authRoles[0]=user keycloak.security-constraints[0].securityCollections[0].patterns[0]=/customers/*

These constraints ensure that every request to /customers/* will only be authorized if the one requesting it is an authenticated user with the role user.

Additionally, we can define keycloak.principal-attribute as preferred_username so as to populate our controller's Principal with a proper user:

keycloak.principal-attribute=preferred_username

5.5. Demonstration

Now, we're ready to test our application. To run a Spring Boot application, we can start it easily through an IDE like Spring Tool Suite (STS) or run this command in the terminal:

mvn clean spring-boot:run

On visiting //localhost:8081 we see:

Now we click customers to enter the intranet, which is the location of sensitive information.

We can see that we've been redirected to authenticate through Keycloak to see if we're authorized to view this content:

Once we log in as user1, Keycloak will verify our authorization – that we have the user role – and we'll be redirected to the restricted customers page:

Now we've finished the set up of connecting Spring Boot with Keycloak and demonstrating how it works.

As we can see, the entire process of calling the Keycloak Authorization Server was handled seamlessly by Spring Boot for us. We did not have to call the Keycloak API to generate the Access Token ourselves, or even send the Authorization header explicitly in our request for protected resources.

Next, we'll be reviewing how to use Spring Security in conjunction with our existing application.

6. Spring Security

There is a Keycloak Spring Security Adapter, and it’s already included in our Spring Boot Keycloak Starter dependency. We'll now see how to integrate Spring Security with Keycloak.

6.1. Dependency

To use Spring Security with Spring Boot, we must add this dependency:

 org.springframework.boot spring-boot-starter-security 2.2.6.RELEASE 

The latest Spring Boot Starter Security release can be found on Maven Central.

6.2. Configuration Class

Keycloak provides a KeycloakWebSecurityConfigurerAdapter as a convenient base class for creating a WebSecurityConfigurer instance.

This is helpful because any application secured by Spring Security requires a configuration class that extends WebSecurityConfigurerAdapter:

@Configuration @EnableWebSecurity @ComponentScan(basePackageClasses = KeycloakSecurityComponents.class) class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { @Autowired public void configureGlobal( AuthenticationManagerBuilder auth) throws Exception { KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); keycloakAuthenticationProvider.setGrantedAuthoritiesMapper( new SimpleAuthorityMapper()); auth.authenticationProvider(keycloakAuthenticationProvider); } @Bean public KeycloakSpringBootConfigResolver KeycloakConfigResolver() { return new KeycloakSpringBootConfigResolver(); } @Bean @Override protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { return new RegisterSessionAuthenticationStrategy( new SessionRegistryImpl()); } @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http.authorizeRequests() .antMatchers("/customers*") .hasRole("user") .anyRequest() .permitAll(); } }

In the code above, the method configureGlobal() tasks the SimpleAuthorityMapper to make sure roles are not prefixed with ROLE_.

Another method, keycloakConfigResolver defines that we want to use the Spring Boot properties file support instead of the default keycloak.json.

Because we've set up the security constraints with Spring Security, we can remove or comment these security constraints we'd placed earlier in the properties file:

#keycloak.security-constraints[0].authRoles[0]=user #keycloak.security-constraints[0].securityCollections[0].patterns[0]=/customers/*

Now, after we authenticate, we'll be able to access the internal customers' page, same as we saw before.

7. Conclusion

In this tutorial, we’ve configured a Keycloak server and used it with a Spring Boot Application.

Видяхме също как да настроим Spring Security и да го използваме заедно с Keycloak. Работна версия на кода, показана в тази статия, е достъпна в Github.