Spring?Boot應(yīng)用程序中如何使用Keycloak詳解
正文
在這篇文章中,我將展示如何在 Spring Boot 應(yīng)用程序中使用 Keycloak。在我們使用 Keycloak 之前,我們將介紹一些關(guān)于 Keycloak 是什么以及我們?yōu)槭裁词褂盟幕A(chǔ)知識(shí)。
要開(kāi)始前,您需要具備以下條件:
- 代碼編輯器——IntelliJ
- 數(shù)據(jù)庫(kù)——MySQL
- Keycloak
- Java 8
什么是Keycloak?
Keycloak是一種用于現(xiàn)代應(yīng)用程序和服務(wù)的開(kāi)源身份和訪問(wèn)管理解決方案。Keycloak 同時(shí)提供 SAML 和 OpenID 協(xié)議解決方案。
我們?yōu)槭裁匆褂肒eycloak?
如前所述,Keycloak 提供身份和訪問(wèn)管理,它也是開(kāi)源的。SAML 和 OpenID 協(xié)議是行業(yè)標(biāo)準(zhǔn)。構(gòu)建與 Keycloak 集成的應(yīng)用程序只會(huì)為您提供更安全和穩(wěn)定的解決方案。當(dāng)然還有其他可用的解決方案,如 Gluu、Shibboleth、WSO2。
對(duì)于這篇文章,我們將使用 Keycloak。
在Spring Boot 應(yīng)用程序中使用keycloak
這個(gè)演示有兩個(gè)部分。一個(gè)是關(guān)于Keycloak。第二個(gè)是關(guān)于使用 Keycloak 保護(hù) Spring Boot 應(yīng)用程序。
安裝Keycloak
在您的機(jī)器上下載Keycloak 。解壓縮下載的文件并使用命令提示符下 bin 目錄中的以下命令運(yùn)行服務(wù)器(注意 – 我在 Windows 機(jī)器上):
standalone.bat -Djboss.socket.binding.port-offset=100
這將在本地計(jì)算機(jī)上為您的 Keycloak 啟動(dòng) Wildfly 服務(wù)器。我們可以通過(guò)執(zhí)行 URL 來(lái)訪問(wèn)服務(wù)器http://localhost:8180。如果您只是使用 standalone.bat 執(zhí)行而沒(méi)有該參數(shù),則服務(wù)器將在端口上運(yùn)行8080。

啟動(dòng)服務(wù)器后,您要做的第一件事就是創(chuàng)建一個(gè)管理員用戶。我們將創(chuàng)建一個(gè)用戶 admin 和密碼 d#n3q2b 。
現(xiàn)在我們將訪問(wèn)管理控制臺(tái)并輸入我們的用戶詳細(xì)信息。一旦我們以管理員用戶身份登錄,我們將看到如下第一個(gè)屏幕:

添加應(yīng)用程序
初始屏幕顯示默認(rèn)領(lǐng)域。出于演示目的,我們將創(chuàng)建一個(gè)新領(lǐng)域SpringBootKeycloakApp。在這個(gè)領(lǐng)域中,我們將添加我們的 Spring Boot 應(yīng)用程序作為客戶端。在“客戶端”選項(xiàng)卡上創(chuàng)建一個(gè)新客戶端。我們將我們的客戶端應(yīng)用程序命名為 SpringBootApp。
現(xiàn)在在設(shè)置中,我們將為我們的 Spring Boot 應(yīng)用程序添加重定向 url。這是 Keycloak 將在身份驗(yàn)證后重定向到我們的應(yīng)用程序的 URL。此外,我們使用 openid connect 作為協(xié)議作為此實(shí)現(xiàn)的一部分。

添加用戶
現(xiàn)在我們將添加一個(gè)我們將用于身份驗(yàn)證的用戶。我們將使用此用戶登錄到我們的示例 Spring Boot 應(yīng)用程序。
在 Keycloak 的角色選項(xiàng)卡上為該用戶添加您想要的角色ROLE_User。完成后,讓我們轉(zhuǎn)到“用戶”選項(xiàng)卡并添加一個(gè)新用戶。

在 Role Mappings 選項(xiàng)卡上,確保為該用戶添加新創(chuàng)建的角色。
創(chuàng)建 Spring Boot 應(yīng)用程序
現(xiàn)在,我們將創(chuàng)建一個(gè)簡(jiǎn)單的 Spring Boot 應(yīng)用程序,它將使用 Keycloak 來(lái)確保安全。作為此應(yīng)用程序的一部分,我們將為將通過(guò)應(yīng)用程序進(jìn)行身份驗(yàn)證的用戶顯示待辦事項(xiàng)列表任務(wù)。
要構(gòu)建此應(yīng)用程序,我們需要以下依賴(lài)項(xiàng):
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'
}
如您所見(jiàn),我們正在使用spring-bootandspring-security以及keycloak-spring-boot-starter依賴(lài)項(xiàng)。
keycloak 依賴(lài)項(xiàng)包括 Keycloak 客戶端適配器。我們將使用這些適配器進(jìn)行身份驗(yàn)證。它們將取代我們的標(biāo)準(zhǔn) Spring Security 適配器。為了確保此keycloak-spring-boot-starter依賴(lài)項(xiàng)正常工作,我們需要在我們的 gradle 文件中添加一個(gè)依賴(lài)項(xiàng),如下所示:
dependencyManagement {
imports {
mavenBom "org.keycloak.bom:keycloak-adapter-bom:11.0.2"
}
}
要了解更多相關(guān)信息,您可以訪問(wèn)keycloak的官方文檔。
我們的 Controller 類(lèi)將有兩個(gè)重要的方法,一個(gè)是獲取任何人都可以訪問(wèn)的主頁(yè),另一個(gè)是獲取任務(wù)列表,只有具有 ROLE_User 角色的經(jīng)過(guò)身份驗(yàn)證的用戶才能訪問(wèn)這些任務(wù)。此 TaskController 的代碼如下所示:
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());
}
}
在這個(gè)控制器類(lèi)中,我們用來(lái)TaskManager獲取所有任務(wù)。我會(huì)解釋 KeyCloakSecurityContext我什么時(shí)候會(huì)展示SecurityConfig。
有沒(méi)有使用Spring-Security
我們可以利用此應(yīng)用程序并使用 Keycloak 進(jìn)行身份驗(yàn)證,無(wú)論是否使用Spring-Security. 作為本演示的一部分,我們使用Spring-Security. 要在沒(méi)有 Spring-Security 的情況下使用相同的應(yīng)用程序,您只需刪除 Spring-Security 依賴(lài)并通過(guò)application.properties文件添加安全配置。
我們需要以下屬性才能application.properties在此應(yīng)用程序中使用 Keycloak 進(jìn)行身份驗(yàn)證。
keycloak.auth-server-url=http://localhost:8180/auth keycloak.realm=SpringBootKeycloakApp keycloak.resource=SpringBootApp keycloak.public-client=true keycloak.principal-attribute=preferred_username
如果我們想在沒(méi)有 Spring-Security 的情況下使用這個(gè)應(yīng)用程序,我們還需要以下兩個(gè)屬性:
keycloak.security-constraints[0].authRoles[0]=ROLE_User keycloak.security-constraints[0].securityCollections[0].patterns[0]=/tasks
由于我們正在使用Spring-Security,所以我們將通過(guò)一個(gè) Java 類(lèi)來(lái)配置安全配置SecurityConfig。
這個(gè) SecurityConfig 類(lèi)將擴(kuò)展KeyCloakWebSecurityConfigurerAdapter.
我們的配置方法如下所示:
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
{
super.configure(httpSecurity);
httpSecurity.authorizeRequests()
.antMatchers("/tasks").hasRole("User")
.anyRequest().permitAll();
}
基本上任何到達(dá) /tasks 端點(diǎn)的請(qǐng)求都應(yīng)該具有 ROLE_User 用戶角色。此處假定 ROLE_ 的前綴。除任何其他請(qǐng)求外,未經(jīng)任何授權(quán)將被允許。在這種情況下,我們將調(diào)用我們的索引頁(yè)面。
我們將使用@KeyCloakConfiguration基本上是封面@Configuration和@EnableWebSecurity注釋的注釋。
由于我們的SecurityConfigextends KeycloakWebSecurityConfigurerAdapter,我們必須實(shí)施 sessionAuthenticationStrategy 和 httpSessionManager 。我們還必須使用 Spring Security Authentication Manager 注冊(cè)我們的 idp Keycloak。
所以我們的 SecurityConfig 將如下所示:
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();
}
}
所以 Spring Security 使用像 ROLE_USER 這樣大寫(xiě)的角色,并且總是使用 ROLE_ 前綴。為了處理這個(gè)問(wèn)題,我在 Keycloak 中添加了一個(gè)角色為 ROLE_User 的用戶,但我們只會(huì)驗(yàn)證一個(gè)前綴,因?yàn)槲覀兊?http 配置無(wú)論如何都會(huì)驗(yàn)證該角色。
由于我們將使用 Keycloak 進(jìn)行身份驗(yàn)證,因此我們需要一個(gè)用于用戶狀態(tài)的會(huì)話。我們?cè)谶@里使用RegisterSessionAuthenticationStrategy。HttpSessionManager是一個(gè)條件 bean,因?yàn)?Keycloak 已經(jīng)實(shí)現(xiàn)了那個(gè) bean。
要實(shí)現(xiàn) Keycloak Spring Boot 適配器,我們將添加一個(gè)KeyCloakSpringBootConfigResolverbean,如下所示:
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();
}
}
應(yīng)用程序演示
運(yùn)行我們的 keycloak 應(yīng)用程序,它將在http://localhost:8180上運(yùn)行。我們的 Spring Boot 應(yīng)用程序?qū)⒃趆ttp://localhost:8080運(yùn)行。
我們的 Spring Boot 應(yīng)用程序的第一個(gè)屏幕如下所示:

現(xiàn)在,如果用戶點(diǎn)擊獲取所有任務(wù),他將被重定向到 Keycloak 登錄屏幕,如下所示:

現(xiàn)在,我將輸入我的用戶 betterjavacode 用戶名和密碼,它將向我們顯示我們的任務(wù)列表,如下所示:

認(rèn)證流程
當(dāng)用戶單擊“獲取所有任務(wù)”時(shí),用戶將被重定向到 Spring Security 的 sso/login 端點(diǎn),KeycloakSpringBootConfigResolver 處理該端點(diǎn)并向 Keycloak 發(fā)送授權(quán)代碼流請(qǐng)求
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 將處理請(qǐng)求以響應(yīng)會(huì)話代碼并顯示登錄屏幕。
一旦用戶輸入憑據(jù)并且 keycloak 驗(yàn)證了這些憑據(jù),它將使用授權(quán)代碼進(jìn)行響應(yīng),并將此代碼交換為令牌,然后用戶登錄。
結(jié)論
在這篇文章中,展示了如何使用 Keycloak 作為身份提供者來(lái)保護(hù)您的 Spring Boot 應(yīng)用程序。這樣 一個(gè)簡(jiǎn)單的程序就完成了!
以上就是Spring Boot應(yīng)用程序中如何使用Keycloak詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring Boot使用Keycloak的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot3.x中Jakarta包無(wú)法引入的問(wèn)題
最近想將一些項(xiàng)目升級(jí)到springboot3.x和java17的時(shí)候,發(fā)現(xiàn)項(xiàng)目依賴(lài)中有Jakarta的包,但是代碼標(biāo)紅提示沒(méi)有相關(guān)的類(lèi),本文就來(lái)介紹一下解決方法,感興趣的可以了解一下2024-02-02
Java將對(duì)象寫(xiě)入文件讀出_序列化與反序列化的實(shí)例
下面小編就為大家?guī)?lái)一篇Java將對(duì)象寫(xiě)入文件讀出_序列化與反序列化的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
線程池調(diào)用kafka發(fā)送消息產(chǎn)生的內(nèi)存泄漏問(wèn)題排查解決
這篇文章主要為大家介紹了線程池調(diào)用kafka發(fā)送消息產(chǎn)生的內(nèi)存泄漏問(wèn)題排查解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
詳解Java的文件與目錄管理以及輸入輸出相關(guān)操作
這篇文章主要介紹了詳解Java的文件與目錄管理以及輸入輸出相關(guān)操作,是Java入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09
Java class文件格式之屬性_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
在本文中, 主要講解了class文件中的一些屬性。 這些屬性可以出現(xiàn)在class文件中的對(duì)個(gè)地方, 用來(lái)描述一些其他信息2017-06-06

