Spring Boot 整合 Keycloak

news2024/11/18 13:47:17

1、概览

本文将带你了解如何设置 Keycloak 服务器,以及如何使用 Spring Security OAuth2.0 将 Spring Boot 应用连接到 Keycloak 服务器。

2、Keycloak 是什么?

Keycloak 是针对现代应用和服务的开源身份和访问管理解决方案。

Keycloak 提供了诸如单点登录(SSO)、身份代理和社交登录、用户联盟、客户端适配器、管理控制台和账户管理等功能。

本文使用 Keycloak 的管理控制台,使用 Spring Security OAuth2.0 设置和连接 Spring Boot。

3、设置 Keycloak 服务器

设置和配置 Keycloak 服务器。

3.1、下载和安装 Keycloak

有多种发行版可供选择,本文使 Keycloak-22.0.3 独立服务器发行版。点击 这里 从官方下载。

下载完后,解压缩并从终端启动 Keycloak:

unzip keycloak-22.0.3.zip 
cd keycloak-22.0.3
bin/kc.sh start-dev

运行这些命令后,Keycloak 会启动服务。如果你看到一行类似于 Keycloak 22.0.3 [...] started 的内容,就表示服务器启动成功。

打开浏览器,访问 http://localhost:8080,会被重定向到 http://localhost:8080/auth 以创建管理员进行登录:

创建一个名为 initial1 的初始管理员用户,密码为 zaq1!QAZ。点击 “Create”后,可以看到 “User Created” 的提示信息。

现在进入管理控制台。在登录页面,输入 initial 管理员用户凭证:

3.2、创建 Realm

登录成功后,进入控制台,默认为 Master Realm。

导航到左上角,找到 “Create realm” 按钮:

点击它,添加一个名为 SpringBootKeycloak 的新 Realm:

单击 “Create” 按钮,创建一个新的 Realm。会被重定向到该 Realm。接下来的所有操作都将在这个新的 SpringBootKeycloak Realm 中执行。

3.3、创建客户端

现在进入 “Clients” 页面。如下图所示,Keycloak 已经内置了客户端:

我们需要在应用中添加一个新客户端,点击 “Create”,将新客户端命名为 login-app

在下一步的设置中,除了 “Valid Redirect URIs” 字段外,其他字段保留所有默认值。该字段包含将使用此客户端进行身份验证的应用 URL:

稍后,我们会创建一个运行于 8081 端口的 Spring Boot 应用,该应用将使用该客户端。因此,在上面使用了 http://localhost:8081/ 的重定向 URL。

3.4、创建角色和用户

Keycloak 使用基于角色的访问;因此,每个用户都必须有一个角色。

进入 “Realm Roles” 页面:

然后添加用户角色:

现在有了一个可以分配给用户的角色,但由于还没有用户,让我们去 “Users” 页面添加一个:

添加一个名为 user1 的用户:

用户创建后,会显示一个包含其详细信息的页面:

现在进入 “Credentials” 选项卡。把初始密码设置为 xsw2@WS

最后,进入 “Role Mappings” 选项卡。为 user1 分配用户角色:

4、使用 Keycloak API 生成 Access Token

Keycloak 提供了用于生成和刷新 Access Token 的 REST API,可用于创建自己的登录页面。

首先,向如下 URL 发送 POST 请求,从 Keycloak 获取 Access Token:

http://localhost:8080/realms/SpringBootKeycloak/protocol/openid-connect/token

请求体应包含 x-www-form-urlencoded 格式的参数:

client_id:<your_client_id>
username:<your_username>
password:<your_password>
grant_type:password

这会得到一个 access_token 和一个 refresh_token

每次请求受 Keycloak 保护的资源时,都应使用 Access Token,只需将其放在 Authorization 头中即可:

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

Access Token 过期后,可以通过向上述相同的 URL 发送 POST 请求来刷新 Access Token,但请求中应包含 Refresh Token,而不是用户名和密码:

{
    '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 服务器。

首先,在 pom.xml 中声明 spring-boot-starter-oauth2-client 和 spring-boot-starter-security 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

使用 spring-boot-starter-oauth2-resource-server 将身份验证控制委托给 Keycloak 服务器。它允许我们使用 Keycloak 服务器验证 JWT Token:

<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 Provider 交互,以处理不同授权方式的实际请求逻辑。因此,需要配置 OIDC Provider。它可以根据 Schema spring.security.oauth2.client.provider.[provider name] 的属性值自动配置。

OIDC Provider 配置:

spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username

在 issuer-uri 中指定路径(我们是在 8080 端口启动 Keycloak 的)。该属性标识了授权服务器的基本 URI,输入在 Keycloak 管理控制台中创建的 Realm 名称。此外,还可以将 user-name-attribute 定义为 preferred_username,以便在 Controller 的 Principal 中填充合适的用户。

最后,添加针对 Keycloak 服务器验证 JWT Token 所需的配置:

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()); 
    } 
    @Order(1) 
    @Bean 
    public SecurityFilterChain clientFilterChain(HttpSecurity http) throws Exception { 
        http.authorizeRequests() 
            .requestMatchers(new AntPathRequestMatcher("/")) 
            .permitAll() 
            .anyRequest() 
            .authenticated(); 
        http.oauth2Login() 
            .and() 
            .logout() 
            .addLogoutHandler(keycloakLogoutHandler) 
            .logoutSuccessUrl("/"); 
        return http.build(); 
    } 
     
    @Order(2) 
    @Bean 
    public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception { 
        http.authorizeRequests() 
            .requestMatchers(new AntPathRequestMatcher("/customers*")) 
            .hasRole("USER") 
            .anyRequest() 
            .authenticated(); 
        http.oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));
        return http.build(); 
    } 
    @Bean 
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception { 
        return http.getSharedObject(AuthenticationManagerBuilder.class) 
            .build(); 
    } 
}

在上面的代码中,oauth2Login() 方法将 OAuth2LoginAuthenticationFilter 添加到过滤器链中。该过滤器会拦截请求并应用 OAuth 2 身份验证所需的逻辑。oauth2ResourceServer 方法将根据 Keycloak 服务器验证绑定的 JWT Token。

在 configure() 方法中根据权限和角色配置访问权限。这些约束条件可确保对 /customers/* 的每个请求只有在请求者是具有 USER 角色的经过身份验证的用户时才会获得授权。

最后,添加了 KeycloakLogoutHandler 类来处理 Keycloak 注销:

@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 发送注销请求。

现在,通过身份验证后,就可以访问内部 customers 页面了。

5.4、Thymeleaf Web 页面

使用 Thymeleaf 渲染页面。

有三个页面:

  • external.html - 面向外部的页面
  • customers.html - 面向内部的页面,其访问权限仅限于具有 user 角色的认证用户
  • layout.html - 一个简单的布局,由两个片段组成,分别用于面向外部的页面和面向内部的页面

Thymeleaf 模板的代码可在 Github 上获取。

5.5、Controller

Web Controller 会将内部和外部 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 会从 Repository 中检索所有客户,并将结果作为属性添加到 Model 中。之后,在 Thymeleaf 中遍历结果。

为了能够显示用户名,还注入了 Principal

注意,这里只是将客户(customers)作为原始数据来显示,仅此而已。

6、演示

现在,测试应用。通过集成开发环境(如 Spring Tool Suite - STS)运行 Spring Boot 应用,或者在终端运行如下命令:

mvn clean spring-boot:run

访问 http://localhost:8081,如下:

现在,点击 “customers” 户进入内部页面,这是敏感信息的位置。

然后会被重定向到通过 Keycloak 进行身份验证,以检查我们是否被授权查看此内容:

用 user1 的凭证登录,Keycloak 会验证我们的授权,确认我们拥有用户角色,然后会被重定向到受限的 “customers” 页面:

现在,整个流程已经完毕了。你可以看到,Spring Boot 无缝地处理了调用 Keycloak 授权服务器的整个过程。我们无需调用 Keycloak API 自己生成 Access Token,甚至无需在请求受保护资源时明确发送 Authorization 头。

7、总结

本文介绍了如何如何设置了 Keycloak 服务器,以及如何在 Spring Boot 中使用 Spring Security OAuth2.0 结合 Keycloak 实现认证和授权。


Ref:https://www.baeldung.com/spring-boot-keycloak

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2175402.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

秦巴山区SHP格式矢量范围

‌秦巴山区的shp范围包括河南、湖北、重庆、四川、陕西、甘肃六省市的80个县(市、区)。‌这一区域不仅地理范围广泛&#xff0c;而且生态多样性丰富&#xff0c;是国家重要的生物多样性和水源涵养生态功能区。秦巴山区的地貌类型以山地丘陵为主&#xff0c;间有汉中、安康、商丹…

Centos8.5.2111(1)之本地yum源搭建和docker部署与网络配置

由于后边可能要启动多个服务&#xff0c;避免服务之间相互干扰&#xff0c;本课程建议每个服务独立部署到一台主机上&#xff0c;这样做会导致资源占用过多&#xff0c;可能会影响系统的运行。服务器部署一般不采用GUI图形界面部署&#xff0c;而是采用命令行方式部署&#xff…

lDE 使用技巧与插件推荐(含案例说明)

在使用集成开发环境&#xff08;IDE&#xff09;进行编程时&#xff0c;掌握一些技巧和使用高效的插件可以显著提高开发效率。以下是一些通用的IDE使用技巧和插件推荐&#xff0c;适用于多种流行的IDE&#xff0c;如IntelliJ IDEA、Visual Studio Code、PyCharm等。每个技巧和插…

IEEE GRSL投稿历程分享

投稿期刊&#xff1a;IEEE geoscience and remote sensing 本人为本科生&#xff0c;在投这本期刊时已经经历了三次拒稿&#xff08;两次RS&#xff0c;一次GRSL&#xff09;&#xff0c;被RS拒稿意料之中&#xff0c;因为工作量并不是特别大&#xff0c;所以写得比较短&#…

【RocketMQ】RocketMQ快速入门

&#x1f3af; 导读&#xff1a;该文档介绍了Apache RocketMQ消息队列的基础应用&#xff0c;包括消息发送与接收的基本流程。首先通过创建生产者实例&#xff0c;并指定名称服务器地址&#xff0c;启动后即可发送消息至指定主题。然后创建消费者实例订阅相应主题&#xff0c;并…

js逆向——webpack实战案例(一)

今日受害者网站&#xff1a;https://www.iciba.com/translate?typetext 首先通过跟栈的方法找到加密位置 我们跟进u函数&#xff0c;发现是通过webpack加载的 向上寻找u的加载位置&#xff0c;然后打上断点&#xff0c;刷新网页&#xff0c;让程序断在加载函数的位置 u r.n…

Mamba模型初步解析 — Mamba : Linear-Time Sequence Modeling with Selective State Spaces

Mamba模型初步接触 — Mamba : Linear-Time Sequence Modeling with Selective State Spaces "Mamba"是一种序列建模架构&#xff0c;它采用了称为选择性状态空间模型&#xff08;SSMs&#xff09;的结构来优化处理长序列数据的效率和性能&#xff0c;这在语言处理、…

如果只能保留一个复制粘贴软件,那一定是它pastemate

下载地址&#xff1a;Pastemate 在日常的工作和生活中&#xff0c;使用电脑必离不开的功能中&#xff0c;一定有复制粘贴。传统的复制粘贴方式效率不那么高&#xff0c;Windows内置的剪切板功能感觉又差那么些意思。 &#x1f9d0;对于功能和颜值都有要求的你&#xff0c;一定…

端口隔离配置的实验

端口隔离配置是一种网络安全技术&#xff0c;用于在网络设备中实现不同端口之间的流量隔离和控制。以下是对端口隔离配置的详细解析&#xff1a; 基本概念&#xff1a;端口隔离技术允许用户将不同的端口加入到隔离组中&#xff0c;从而实现这些端口之间的二层数据隔离。这种技…

Linux入门2——初识Linux权限

目录 0. Linux下的用户 1.文件访问者的分类 2.文件类型和访问权限 3. 文件权限值的表示方法 4.文件访问权限的相关设置方法 4.1 修改文件的访问权限 4.2修改文件的拥有者和所属组 0. Linux下的用户 在学习Linux权限之前&#xff0c;我们要先来了解Linux下的用户&#x…

(十七)、Mac 安装k8s

文章目录 1、Enable Kubernetes2、查看k8s运行状态3、启用 kubernetes-dashboard3.1、如果启动成功&#xff0c;可以在浏览器访问3.2、如果没有跳转&#xff0c;需要单独安装 kubernetes-dashboard3.2.1、方式一&#xff1a;一步到位3.2.2、方式二&#xff1a;逐步进行 1、Enab…

杭州网站设计中的常见误区及解决方案

在杭州网站设计领域&#xff0c;随着数字经济的快速发展&#xff0c;越来越多的企业意识到互联网的重要性。然而&#xff0c;在实际的网站设计过程中&#xff0c;仍然存在一些常见的误区&#xff0c;这些误区可能会影响用户体验和网站的整体效果。以下是几种普遍存在的误区及其…

国产动漫论坛系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;动漫分类管理&#xff0c;动漫视频管理&#xff0c;动漫图片管理&#xff0c;动漫文章管理&#xff0c;交流论坛&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&a…

汇编语言 访问CMOS RAM并打印时间(未完)

题目:以"年/月/日 时:分:秒"的格式,显示当前的日期,时间 提示:在此代码的基础上加以改造 assume cs:code code segment start:mov al,9 ;年out 70h,al ;传入9号单元的地址in al,71h ;取9号单元的内容&#xff0c;高4位为十位、低4位为各位mov ah,almov cl,4shr ah,…

1-仙灵之谜(区块链游戏详情介绍)

1-仙灵之谜&#xff08;区块链游戏详情介绍&#xff09; 前言&#xff08;该游戏仅供娱乐&#xff09;正文 前言&#xff08;该游戏仅供娱乐&#xff09; 依稀记得本科那会儿参加了一个区块链实验室&#xff0c;那时每周末大家都会爬山或者抽出一下午讨论区块链以及未来&#x…

< 初等物理 >

SI国际单位制 常见的公制单位 为什么需要单位&#xff0c;是统一衡量的标准 通过国际单位&#xff0c;以及单位的拓展&#xff0c;以及单位的组合&#xff0c;形成一系列新的测量单位 面积 m^2 速率 m/s 米每二次方秒&#xff0c;m / s, delta表示增量, 每秒移动多少米 加…

pdf怎么转变成jpg图片?值得推荐的几种PDF转jpg方法

pdf怎么转变成jpg图片&#xff1f;jpg格式的图像在电子邮件、社交媒体等在线平台上分享非常方便&#xff0c;用户无需担心软件兼容性问题。将PDF内容转换为jpg后&#xff0c;能够有效保留原始文档的视觉布局&#xff0c;使信息更加生动易懂&#xff0c;适合用于演示和展示。同时…

【小沐学GIS】基于ubuntu+three.js的OSM建筑模型显示(node.js、Python)

文章目录 1、简介1.1 ubuntu1.2 node1.3 python1.4 osm1.5 three.js 2、安装ubuntu3、安装node4、安装python结语 1、简介 1.1 ubuntu https://cn.ubuntu.com/download https://ubuntu.com/download Ubuntu是一个以桌面应用为主的Linux发行版操作系统&#xff0c;其名称来自非…

萝卜大杂烩 | 快速掌控seaborn(画图必备)

本文来源公众号“萝卜大杂烩”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;快速掌控seaborn Matplotlib绘制一张美图需要很多参数调整&#xff0c;于是就出现了high-level版的Seaborn&#xff0c;几行代码即可输出美美的图形&am…

超详细的 GitHub 个人主页美化教程

Guthub 个人主页 &#xff08;官方称呼是 profile&#xff09;可以展示很多有用的信息&#xff0c;例如添加一个首页被访问次数的计数器&#xff0c;一个被 Star 与 Commit 的概览信息&#xff0c;以及各种技能标签&#xff0c;设备标签等&#xff0c;还可以利用 wakatime 显示…