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

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

添加應(yīng)用程序
初始屏幕顯示默認(rèn)領(lǐng)域。出于演示目的,我們將創(chuàng)建一個新領(lǐng)域SpringBootKeycloakApp。在這個領(lǐng)域中,我們將添加我們的 Spring Boot 應(yīng)用程序作為客戶端。在“客戶端”選項(xiàng)卡上創(chuàng)建一個新客戶端。我們將我們的客戶端應(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)在我們將添加一個我們將用于身份驗(yàn)證的用戶。我們將使用此用戶登錄到我們的示例 Spring Boot 應(yīng)用程序。
在 Keycloak 的角色選項(xiàng)卡上為該用戶添加您想要的角色ROLE_User。完成后,讓我們轉(zhuǎn)到“用戶”選項(xiàng)卡并添加一個新用戶。

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

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

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

認(rèn)證流程
當(dāng)用戶單擊“獲取所有任務(wù)”時,用戶將被重定向到 Spring Security 的 sso/login 端點(diǎn),KeycloakSpringBootConfigResolver 處理該端點(diǎn)并向 Keycloak 發(fā)送授權(quán)代碼流請求
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 將處理請求以響應(yīng)會話代碼并顯示登錄屏幕。
一旦用戶輸入憑據(jù)并且 keycloak 驗(yàn)證了這些憑據(jù),它將使用授權(quán)代碼進(jìn)行響應(yīng),并將此代碼交換為令牌,然后用戶登錄。
結(jié)論
在這篇文章中,展示了如何使用 Keycloak 作為身份提供者來保護(hù)您的 Spring Boot 應(yīng)用程序。這樣 一個簡單的程序就完成了!
以上就是Spring Boot應(yīng)用程序中如何使用Keycloak詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring Boot使用Keycloak的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot本地調(diào)試沒問題,打包運(yùn)行報錯原因及分析
這篇文章主要介紹了springboot本地調(diào)試沒問題,打包運(yùn)行報錯原因及分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05
java.lang.ArrayStoreException異常的解決方案
這篇文章主要介紹了java.lang.ArrayStoreException異常的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
修改idea的這些啟動參數(shù),令你的idea健步如飛
這篇文章主要介紹了修改idea的這些啟動參數(shù),令你的idea健步如飛~具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
springboot構(gòu)建docker鏡像并推送到阿里云
本文主要介紹了springboot構(gòu)建docker鏡像并推送到阿里云,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
Spring實(shí)現(xiàn)HikariCP連接池的示例代碼
在SpringBoot 2.0中,我們使用默認(rèn)連接池是HikariCP,本文講一下HikariCP的具體使用,具有一定的參考價值,感興趣的可以了解一下2021-08-08

