网站首页 > 精选文章 / 正文
1. 概述
在本文中,我们将讨论设置 Keycloak 服务器并使用 Spring Security OAuth2.0 将 Spring Boot 应用程序连接到它的基础知识。
2. 什么是Keycloak?
Keycloak 是一个面向现代应用程序和服务的开源身份和访问管理解决方案。Keycloak 提供单点登录 (SSO)、身份代理和社交登录、用户联合、客户端适配器、管理控制台和帐户管理控制台等功能。
3. 设置Keycloak服务器
在本节中,我们将设置和配置 Keycloak 服务器。
3.1. 下载和安装Keycloak
有多种发行版可供选择。我们将使用独立版本。从官方来源下载Keycloak-20.0.3独立服务器发行版。下载独立服务器发行版后,我们可以从终端解压缩并启动Keycloak:
$ unzip keycloak-20.0.3.zip
$ cd keycloak-20.0.3
$ bin/kc.sh start-dev
运行这些命令后,Keycloak将启动其服务。一旦我们看到包含Keycloak 20.0.3 [...] 的行启动,我们就知道它的启动已经完成。
现在让我们打开浏览器并访问 http://localhost:8080。 我们将被重定向到 http://localhost:8080/auth 以创建管理登录名:
让我们使用密码 zaq1!QAZ 创建一个名为 initial1 的初始管理员用户。单击“创建”后,我们将看到消息“用户已创建”。
现在,我们可以进入管理控制台了。在登录页面上,我们将输入初始管理员用户和密码:
3.2. 创建领域
成功登录将带我们进入控制台并为我们打开默认的主领域。在这里,我们将重点介绍如何创建自定义领域。让我们导航到左上角以发现“创建领域”按钮:
添加一个名为 SpringBootKeycloak 的新领域:
单击“创建”按钮后,将创建一个新领域,我们将被重定向到该领域。下一节中的所有操作都将在这个新的 SpringBootKeycloak 领域中执行。
3.3. 创建客户端
现在我们将导航到“客户端”页面。如下图所示,Keycloak附带了已经内置的客户端:
仍然需要向应用程序添加新客户端,因此我们将单击“创建”。我们将新的客户端登录应用程序称为:
我们将保留除“有效重定向 URI”字段之外的所有默认值。此字段应包含将使用此客户端进行身份验证的应用程序 URL:
稍后,我们将创建一个在端口 8081 上运行的 Spring 启动应用程序,该应用程序将使用此客户端。因此,我们使用了上面的 http://localhost:8081/* 重定向 URL。
3.4. 创建角色和用户
Keycloak使用基于角色的访问;因此,每个用户都必须具有一个角色。为此,我们需要导航到 Realm 角色页面:
然后,我们将添加用户角色:
现在我们有一个可以分配给用户的角色,但由于还没有用户,让我们转到“用户”页面并添加一个:
我们将添加一个名为 user1 的用户:
创建用户后,将显示一个包含其详细信息的页面:
我们现在可以转到“凭据”选项卡。我们将初始密码设置为 xsw2@WS:
最后,我们将导航到“角色映射”选项卡。我们将用户角色分配给user1:
4. 使用 Keycloak 的 API 生成访问令牌
Keycloak 提供了一个 REST API,用于生成和刷新访问令牌。我们可以轻松地使用此API来创建自己的登录页面。
首先,我们需要通过向此 URL 发送 POST 请求来从 Keycloak 获取访问令牌:
http://localhost:8080/realms/SpringBootKeycloak/protocol/openid-connect/token
请求应具有 x-www-form-urlencoding 格式的此正文:
client_id:<your_client_id>
username:<your_username>
password:<your_password>
grant_type:password
作为回应,我们将得到一个access_token和一个refresh_token。
访问令牌应在对受 Keycloak 保护的资源的每个请求中使用,只需将其放在授权标头中:
headers: {
'Authorization': 'Bearer' + access_token
}
访问令牌过期后,我们可以通过向与上述相同的 URL 发送 POST 请求来刷新它,但包含刷新令牌而不是用户名和密码:
{
'client_id': 'your_client_id',
'refresh_token': refresh_token_from_previous_request,
'grant_type': 'refresh_token'
}
Keycloak将以新的access_token和refresh_token来回应这一点。
5. 创建和配置 Spring Boot应用程序
在本节中,我们将创建一个 Spring Boot 应用程序,并将其配置为 OAuth 客户端以与 Keycloak 服务器进行交互。
5.1. 依赖关系
我们使用 Spring Security OAuth2.0 客户端连接到 Keycloak 服务器。让我们首先在Spring Boot 应用程序的pom.xml中声明 spring-boot-starter-oauth2-client 依赖关系:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
另外,由于我们需要在 Spring Boot 中使用 Spring Security,因此我们必须添加此依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
为了将标识控制委托给Keycloak服务器,我们将使用spring-boot-starter-oauth2-resource-server库。它将允许我们使用Keycloak服务器验证JWT令牌。因此,让我们将其添加到我们的pom中:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
现在,Spring Boot 应用程序可以与 Keycloak 交互。
5.2. Keycloak配置
我们将Keycloak客户端视为OAuth客户端。因此,我们需要将 Spring Boot应用程序配置为使用 OAuth 客户端。
ClientRegistration类保存有关客户端的所有基本信息。Spring 自动配置使用模式 spring.security.oauth2.client.registration.[registrationId],并向OAuth 2.0或OpenID Connect (OIDC)注册客户端。让我们配置客户端注册配置:
spring.security.oauth2.client.registration.keycloak.client-id=login-app
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.scope=openid
client-id 的值和在管理控制台中指定的客户端匹配。Spring Boot应用程序需要与 OAuth 2.0 或 OIDC 提供程序交互,以处理不同授权类型的实际请求逻辑。因此,我们需要配置 OIDC 提供程序。可以使用架构 spring.security.oauth2.client.provider.[provider name]。
让我们配置 OIDC 提供程序配置:
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
回想一下,我们在端口 8080 上启动了 Keycloak,因此在 issuer-uri 中指定了路径。此属性标识授权服务器的基本 URI。我们输入我们在Keycloak管理控制台中创建的领域名称。此外,我们可以将用户名属性定义为preferred_username以便使用适当的用户填充控制器的主体。
最后,让我们添加针对 Keycloak 服务器验证 JWT 令牌所需的配置:
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak
5.3. 配置类
我们通过创建一个 SecurityFilterChain bean 来配置 HttpSecurity。此外,我们需要使用 http.oauth2Login() 启用 OAuth2 登录。
让我们创建security配置:
@Configuration
@EnableWebSecurity
class SecurityConfig {
private final KeycloakLogoutHandler keycloakLogoutHandler;
SecurityConfig(KeycloakLogoutHandler keycloakLogoutHandler) {
this.keycloakLogoutHandler = keycloakLogoutHandler;
}
@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/customers*")
.hasRole("USER")
.anyRequest()
.permitAll();
http.oauth2Login()
.and()
.logout()
.addLogoutHandler(keycloakLogoutHandler)
.logoutSuccessUrl("/");
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return http.build();
}
}
在上面的代码中,oauth2Login() 方法将 OAuth2LoginAuthenticationFilter 添加到过滤器链中。此筛选器截获请求并应用 OAuth 2 身份验证所需的逻辑。oauth2ResourceServer 方法将针对我们的 Keycloak 服务器验证绑定的 JWT 令牌。
我们根据 configure() 方法中的权限和角色配置访问权限。这些约束可确保只有具有角色 USER且经过身份验证的用户才会允许访问/customers/*。
最后,我们需要处理从Keycloak注销。为此,我们添加了KeycloakLogoutHandler类:
@Component
public class KeycloakLogoutHandler implements LogoutHandler {
private static final Logger logger = LoggerFactory.getLogger(KeycloakLogoutHandler.class);
private final RestTemplate restTemplate;
public KeycloakLogoutHandler(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public void logout(HttpServletRequest request, HttpServletResponse response,
Authentication auth) {
logoutFromKeycloak((OidcUser) auth.getPrincipal());
}
private void logoutFromKeycloak(OidcUser user) {
String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
UriComponentsBuilder builder = UriComponentsBuilder
.fromUriString(endSessionEndpoint)
.queryParam("id_token_hint", user.getIdToken().getTokenValue());
ResponseEntity<String> logoutResponse = restTemplate.getForEntity(
builder.toUriString(), String.class);
if (logoutResponse.getStatusCode().is2xxSuccessful()) {
logger.info("Successfulley logged out from Keycloak");
} else {
logger.error("Could not propagate logout to Keycloak");
}
}
}
KeycloakLogoutHandler 类实现 LogoutHandler 类,并将注销请求发送到 Keycloak。
现在,在进行身份验证后,我们将能够访问内部客户页面。
5.4. Thymeleaf网页
我们在网页上使用Thymeleaf。我们有三页:
- external.html – 面向公众的面向外部的网页
- customers.html– 面向内部的页面,其访问权限将仅限于具有角色“user”的经过身份验证的用户
- layout.html – 一个简单的布局,由两个片段组成,用于面向外部的页面和面向内部的页面
5.5. Controller
Web 控制器将内部和外部 URL 映射到相应的 Thymeleaf 模板:
@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";
}
对于路径 /customers,我们将从存储库中检索所有客户,并将结果作为属性添加到模型中。稍后,我们将在Thymeleaf中遍历所有的结果。为了能够显示用户名,我们还注入了主体。我们应该注意,我们在这里使用的客户只是作为要显示的原始数据,仅此而已。
6. 演示
现在,我们已准备好测试我们的应用程序。要运行 Spring Boot 应用程序,我们可以通过 IDE 轻松启动它,例如 Spring Tool Suite (STS),或者在终端中运行以下命令:
mvn clean spring-boot:run
在访问 http://localhost:8081 时,我们看到:
现在我们点击客户进入内网,这是敏感信息的位置。请注意,我们已被重定向到通过 Keycloak 进行身份验证,以查看我们是否有权查看此内容:
一旦我们以user1身份登录,Keycloak将验证我们是否具有用户角色的授权,我们将被重定向到受限客户页面:
现在我们已经完成了将 Spring Boot 与 Keycloak 连接并演示其工作原理的设置。
正如我们所看到的,Spring Boot 无缝地处理了调用 Keycloak 授权服务器的整个过程。我们不必调用 Keycloak API 来自己生成访问令牌,甚至不必在对受保护资源的请求中显式发送授权标头。
Tags:spring tools suite
猜你喜欢
- 2025-01-04 DISMTools v0.5.1 Update 2 DISM管理和操作 Windows 映像 (WIM) 文件
- 2025-01-04 Ubuntu发布最新版本23.04 ,代号月虾(Lunar Lobster)
- 2025-01-04 ATI VISION标定及数据采集解决方案
- 2025-01-04 2016上半年度推荐!10个必用的免费Plugins清单!
- 2025-01-04 Pro Tools 2024.10 - 错误修复
- 2025-01-04 使用LEADTOOLS开发PACS存储服务器
- 2025-01-04 多核ECU的架构挑战及分析工具
- 2025-01-04 雅马哈Steinberg UR22C桌面级声卡,Vlog小白也能畅玩直播录播
- 2025-01-04 基于SpringBoot从0到1编写一个图书管理系统(附源码)
- 2025-01-04 5个神奇的PPT插件,每一个都是宝藏,颠覆了我对PPT的认识