Der endgültige Leitfaden zur Verwendung von Keycloak mit einer Spring Boot-Anwendung
In diesem Beitrag werde ich zeigen, wie man Keycloak in einer Spring Boot-Anwendung verwendet. Bevor wir Keycloak verwenden, werden wir einige Grundlagen darüber behandeln, was Keycloak ist und warum wir es verwenden.
Um mit dieser Demo zu beginnen, benötigen Sie die folgenden Dinge:
- Ein Code-Editor – IntelliJ
- Datenbank – MySQL
- Schlüsselumhang
- Java 8
Was ist Keycloak?
Keycloak ist eine Open-Source-Identitäts- und Zugriffsverwaltungslösung für moderne Anwendungen und Dienste. Keycloak bietet sowohl SAML- als auch OpenID-Protokolllösungen.
Warum verwenden wir Keycloak?
Wie bereits erwähnt, bietet Keycloak Identitäts- und Zugriffsverwaltung, es ist auch Open Source. SAML- und OpenID-Protokolle sind Industriestandards. Das Erstellen einer Anwendung, die in Keycloak integriert ist, bietet Ihnen nur eine sicherere und stabilere Lösung. Es gibt definitiv andere Lösungen wie Gluu, Shibboleth, WSO2 und Okta.
Für diesen Beitrag verwenden wir Keycloak.
Spring Boot-Anwendung mit Keycloak sichern
Diese Demo besteht aus zwei Teilen. Einer handelt von Keycloak. Die zweite betrifft das Sichern der Spring Boot-Anwendung mit Keycloak.
Keycloak installieren
Laden Sie den Keyclon auf Ihren Computer herunter. Entpacken Sie die heruntergeladene Datei und führen Sie den Server mit dem folgenden Befehl aus dem bin-Verzeichnis an Ihrer Eingabeaufforderung aus (Hinweis – ich arbeite auf einem Windows-Computer):
standalone.bat -Djboss.socket.binding.port-offset=100
Dadurch wird Wildfly
gestartet Server für Ihr Keycloak auf Ihrem lokalen Rechner. Wir können auf den Server zugreifen, indem wir die URL http://localhost:8180
ausführen . Wenn Sie nur standalone.bat
verwenden ohne diesen Parameter auszuführen, wird der Server auf dem Port 8080
ausgeführt .
Sobald Sie den Server gestartet haben, müssen Sie als Erstes einen Admin-Benutzer erstellen. Wir erstellen einen Benutzer admin
und Passwort d#n3q2b
.
Jetzt greifen wir auf die Verwaltungskonsole zu und geben unsere Benutzerdaten ein. Sobald wir uns als admin
anmelden Benutzer, sehen wir den ersten Bildschirm wie folgt:
Anwendung hinzufügen
Anfangsbildschirme zeigen den Standardbereich. Für unsere Demozwecke erstellen wir einen neuen Realm SpringBootKeycloakApp
. In diesem Bereich fügen wir unsere Spring Boot-Anwendung als Client hinzu. Erstellen Sie einen neuen Kunden auf der Registerkarte Kunden. Wir nennen unsere Client-Anwendung SpringBootApp
.
Jetzt fügen wir in den Einstellungen redirect url
hinzu für unsere Spring Boot-Anwendung. Dies ist die URL, über die Keycloak nach der Authentifizierung zu unserer App umleitet. Außerdem verwenden wir openid connect
als Protokoll als Teil dieser Implementierung.
Benutzer hinzufügen
Jetzt fügen wir einen Benutzer hinzu, den wir zur Authentifizierung verwenden. Wir werden diesen Benutzer verwenden, um uns bei unserer Spring Boot-Beispielanwendung anzumelden.
Fügen Sie eine gewünschte Rolle für diesen Benutzer ROLE_User
hinzu auf der Registerkarte Rollen in Keycloak. Sobald dies erledigt ist, gehen wir zur Registerkarte Benutzer und fügen einen neuen Benutzer hinzu.
Auf der Role Mappings
Stellen Sie sicher, dass Sie die neu erstellte Rolle für diesen Benutzer hinzufügen.
Erstellen Sie eine Spring Boot-Anwendung
Jetzt erstellen wir eine einfache Spring Boot-Anwendung, die Keycloak für die Sicherheit verwendet. Als Teil dieser Anwendung zeigen wir dem Benutzer, der sich bei der Anwendung authentifiziert, eine Liste mit To-Do-Listen-Aufgaben.
Um diese App zu erstellen, benötigen wir die folgenden Abhängigkeiten:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.keycloak:keycloak-spring-boot-starter'
runtimeOnly 'mysql:mysql-connector-java'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.springframework.security:spring-security-test'
}
Wie Sie sehen können, verwenden wir spring-boot
und spring-security
zusammen mit keycloak-spring-boot-starter
Abhängigkeit.
Die keycloak
Abhängigkeit umfasst Keycloak-Client-Adapter. Wir verwenden diese Adapter für Authentifizierungszwecke. Sie ersetzen unsere standardmäßigen Spring Security-Adapter. Um dies sicherzustellen keycloak-spring-boot-starter
Abhängigkeit korrekt funktioniert, benötigen wir eine weitere Abhängigkeit, die in unserer Gradle-Datei wie folgt hinzugefügt werden muss:
dependencyManagement {
imports {
mavenBom "org.keycloak.bom:keycloak-adapter-bom:11.0.2"
}
}
Um mehr darüber zu erfahren, können Sie die offizielle Dokumentation von keycloak besuchen.
Unsere Controller-Klasse verfügt über zwei wichtige Methoden, eine zum Abrufen der Homepage, auf die jeder zugreifen kann, und eine andere zum Abrufen der Liste der Aufgaben, auf die nur authentifizierte Benutzer mit einer Rolle ROLE_User
zugreifen können . Der Code für diesen TaskController
wird wie folgt aussehen:
package com.betterjavacode.keycloakdemo.keycloakdemo.controllers;
import com.betterjavacode.keycloakdemo.keycloakdemo.dto.TaskDto;
import com.betterjavacode.keycloakdemo.keycloakdemo.managers.TaskManager;
import org.keycloak.KeycloakSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Controller
public class TaskController
{
private final HttpServletRequest request;
@Autowired
public TaskController(HttpServletRequest request)
{
this.request = request;
}
@Autowired
private TaskManager taskManager;
@GetMapping(value="/")
public String home()
{
return "index";
}
@GetMapping(value="/tasks")
public String getTasks(Model model)
{
List tasks = taskManager.getAllTasks();
model.addAttribute("tasks", tasks);
model.addAttribute("name", getKeycloakSecurityContext().getIdToken().getGivenName());
return "tasks";
}
private KeycloakSecurityContext getKeycloakSecurityContext()
{
return (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
}
}
In dieser Controller-Klasse verwenden wir TaskManager
um alle Aufgaben zu bekommen. Ich werde KeyCloakSecurityContext
erklären wenn ich über SecurityConfig
zeige .
Mit oder ohne Spring-Security
Wir können diese Anwendung nutzen und Keycloak für die Authentifizierung mit oder ohne Spring-Security
verwenden . Als Teil dieser Demo verwenden wir Spring-Security
. Um dieselbe Anwendung ohne Spring-Security
zu verwenden , können Sie einfach den Spring-Security
entfernen Abhängigkeit und fügen Sie die Sicherheitskonfiguration durch application.properties
hinzu Datei.
Wir benötigen die folgenden Eigenschaften in application.properties
um Keycloak für die Authentifizierung in dieser App zu verwenden.
keycloak.auth-server-url=http://localhost:8180/auth
keycloak.realm=SpringBootKeycloakApp
keycloak.resource=SpringBootApp
keycloak.public-client=true
keycloak.principal-attribute=preferred_username
Wenn wir diese Anwendung ohne Spring-Security verwenden möchten, benötigen wir auch die folgenden zwei Eigenschaften:
keycloak.security-constraints[0].authRoles[0]=ROLE_User
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/tasks
Da wir Spring-Security verwenden, konfigurieren wir die Sicherheitskonfiguration über eine Java-Klasse SecurityConfig
.
Dieser SecurityConfig
Klasse erweitert KeyCloakWebSecurityConfigurerAdapter
.
Unser configure
Methode sieht wie folgt aus:
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
{
super.configure(httpSecurity);
httpSecurity.authorizeRequests()
.antMatchers("/tasks").hasRole("User")
.anyRequest().permitAll();
}
Grundsätzlich alle Anfragen, die an /tasks
kommen Endpunkt, sollte die Benutzerrolle ROLE_User
haben . Das Präfix von ROLE_
wird hier vorausgesetzt. Andere als jede andere Anfrage ist ohne Genehmigung zulässig. In diesem Fall rufen wir unsere Indexseite auf.
Wir verwenden die Anmerkung @KeyCloakConfiguration
was im Wesentlichen @Configuration
abdeckt und @EnableWebSecurity
Anmerkungen.
Da unser SecurityConfig
erweitert KeycloakWebSecurityConfigurerAdapter
, müssen wir sessionAuthenticationStrategy
implementieren und httpSessionManager
. Wir müssen auch unseren IDP Keycloak
registrieren mit Spring Security Authentication Manager.
Unsere SecurityConfig sieht also wie folgt aus:
package com.betterjavacode.keycloakdemo.keycloakdemo.config;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.keycloak.adapters.springsecurity.management.HttpSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
@Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder)
{
SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
simpleAuthorityMapper.setPrefix("ROLE_");
KeycloakAuthenticationProvider keycloakAuthenticationProvider =
keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(simpleAuthorityMapper);
authenticationManagerBuilder.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy ()
{
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
@Override
@ConditionalOnMissingBean(HttpSessionManager.class)
protected HttpSessionManager httpSessionManager()
{
return new HttpSessionManager();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
{
super.configure(httpSecurity);
httpSecurity.authorizeRequests()
.antMatchers("/tasks").hasRole("User")
.anyRequest().permitAll();
}
}
Daher verwendet Spring Security Rollen in Großbuchstaben wie ROLE_USER und verwendet immer ROLE_
Präfix. Um das zu handhaben, habe ich einen Benutzer mit einer Rolle ROLE_User
hinzugefügt in Keycloak, aber wir werden nur ein Präfix überprüfen, da unsere http-Konfiguration die Rolle sowieso überprüfen wird.
Da wir uns mit Keycloak authentifizieren, benötigen wir eine Sitzung für den Status des Benutzers. Wir verwenden RegisterSessionAuthenticationStrategy
hier. HttpSessionManager
ist eine bedingte Bean, da Keycloak diese Bean bereits implementiert.
Um den Keycloak Spring Boot-Adapter zu implementieren, fügen wir eine KeyCloakSpringBootConfigResolver-Bean wie folgt hinzu:
package com.betterjavacode.keycloakdemo.keycloakdemo.config;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class KeycloakConfig
{
@Bean
public KeycloakSpringBootConfigResolver keycloakSpringBootConfigResolver()
{
return new KeycloakSpringBootConfigResolver();
}
}
Ich habe den Rest des Anwendungsaufbaus nicht gezeigt, aber der Code für dieses Projekt ist auf GitHub verfügbar.
Demo der Anwendung
Führen Sie unsere Keycloak-Anwendung aus, sie wird auf http://localhost:8180
ausgeführt . Unsere Spring Boot-Anwendung wird unter http://localhost:8080
ausgeführt .
Unser erster Bildschirm der Spring Boot-Anwendung sieht wie folgt aus:
Wenn ein Benutzer jetzt auf Get all tasks
klickt , wird er wie folgt zum Anmeldebildschirm von Keycloak weitergeleitet:
Jetzt gebe ich meinen User betterjavacode-Benutzernamen und mein Passwort ein und es zeigt uns unsere Aufgabenliste wie folgt:
Authentifizierungsablauf
Wenn der Benutzer auf Get all tasks
klickt , wird der Benutzer zu sso/login
von Spring Security umgeleitet Endpunkt, den KeycloakSpringBootConfigResolver verarbeitet und eine Autorisierungscodeflussanforderung an Keycloak
http://localhost:8180/auth/realms/SpringBootKeycloakApp/protocol/openid-connect/auth?response_type=code&client_id=SpringBootApp&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fsso%2Flogin&state=70bd4e28-89e6-43b8-8bea-94c6d057a5cf&login=true&scope=openid
Keycloak verarbeitet die Anfrage, antwortet mit einem Sitzungscode und zeigt den Anmeldebildschirm an.
Sobald der Benutzer Anmeldeinformationen eingibt und Keycloak diese validiert, antwortet es mit einem Autorisierungscode, und dieser Code wird gegen ein Token ausgetauscht, und der Benutzer wird angemeldet.
Schlussfolgerung
In diesem Beitrag habe ich gezeigt, wie Sie Ihre Spring Boot-Anwendung mit Keycloak als Identitätsanbieter sichern können. Wenn Ihnen dieser Beitrag gefallen hat, ziehen Sie bitte in Betracht, meinen Blog hier zu abonnieren.
Referenzen
- Schlüsselumhang – Schlüsselumhang
- Sichern Ihrer Anwendung mit Keycloak – Sichern Sie Ihre Anwendung