当前位置: 首页 > news >正文

OpenID Connect(OIDC)认证--keycloak与springboot项目的整合

OpenID Connect认证–keycloak与springboot项目的整合

文章目录

    • OpenID Connect认证--keycloak与springboot项目的整合
      • 前言
      • 什么是 Keycloak?
      • 项目配置
        • 1. 创建 Spring Boot 项目
        • 2. 设置 Keycloak 服务器
        • 3. 在 Keycloak 中创建 Realm 和 Client
        • 4. 配置 Spring Boot 应用
        • 5. 配置 Spring Security
        • 6. 前端请求调用来具体整合

前言

在现代应用程序中,安全性是至关重要的。为了简化认证和授权流程,许多开发人员选择使用 Keycloak 作为统一的身份和访问管理解决方案。Spring Boot 是一个流行的 Java 框架,通过与 Keycloak 整合,可以轻松实现 OAuth2 和 **OpenID Connect (OIDC)**的身份认证和授权功能。本篇博客将详细介绍如何在 Spring Boot 项目中集成 Keycloak,帮助你快速搭建一个安全的 Web 应用。

什么是 Keycloak?

Keycloak 是一个开源的身份和访问管理工具,支持标准协议如 OAuth2 和 OpenID Connect。它允许开发人员轻松地将身份验证、授权和单点登录(SSO)功能集成到应用程序中。通过 Keycloak,可以管理用户、角色、权限,并将这些管理功能集中化。

关于keycloak的配置我就不在这里赘述,具体请参考博文:什么是Keycloak?怎么样使用Keycloak实现登录和权限验证?

项目配置

我将通过一个 Spring Boot 项目来演示如何集成 Keycloak。

1. 创建 Spring Boot 项目

创建一个springboot项目,并引入下面的依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.keycloak</groupId><artifactId>keycloak-spring-boot-starter</artifactId><version>22.0.1</version> <!-- 根据需要选择合适的版本 --></dependency>
</dependencies>

如果你使用的gradle,也大差不差:

dependencies {implementation(libs.spring.boot.starter.security)implementation(libs.spring.boot.starter.oauth2.client)implementation(libs.spring.boot.starter.oauth2.resource.server)implementation(libs.keycloak.spring.boot.starter)
}

主要就是上述的几个依赖,我使用的gradle来构建项目。

2. 设置 Keycloak 服务器

在整合之前,你需要设置一个 Keycloak 服务器。你可以通过 Docker 快速启动一个 Keycloak 实例:

docker run -d --name keycloak -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin quay.io/keycloak/keycloak:latest start-dev

根据上述的docker容器配置,可以自己设置用户名和密码(均为admin),或者设置成你自己喜欢的方式,具体请参考博文:什么是Keycloak?怎么样使用Keycloak实现登录和权限验证?,或是查看官方文档:keycloak操作手册

由于生产需要我是将keycloak部署在公网上的,大概就是:https://keycloak.xxx.cn/,后面的链接我都用这个来替代。

3. 在 Keycloak 中创建 Realm 和 Client

登录到 Keycloak 管理控制台后:

  1. 创建 Realm: 在左侧菜单中选择 “Add realm”,输入一个名称,例如 myrealm,然后点击 “Create”。

  2. 创建 Client
    在创建好的 Realm 中,导航到 “Clients” 部分,点击 “Create” 创建一个新客户端。
    • Client ID: 输入一个客户端 ID,例如 spring-boot-client
    • Client Protocol: 选择 openid-connect
    • Root URL: 输入 Spring Boot 应用的根 URL,例如 http://localhost:8081
    • Save: 点击 “Save” 保存配置。

在客户端的配置页面,确保 “Access Type” 设置为 confidential 并保存,然后生成并复制客户端的 Secret

上述的信息在后续在配置springboot后端的时候会用到。这部分在这篇博文上也有提到:什么是Keycloak?怎么样使用Keycloak实现登录和权限验证?

4. 配置 Spring Boot 应用

application.ymlapplication.properties 中,添加 Keycloak 配置信息:

spring:application:name: customer_managementsecurity:oauth2:client:registration:keycloak:client-id: web_appauthorization-grant-type: implicitscope:- openidprovider:keycloak:issuer-uri: https://keycloak.scysn.cn/realms/testuser-name-attribute: preferred_usernameresource server:jwt:issuer-uri: https://keycloak.scysn.cn/realms/test
server:port: 8081
application:security:oauth2:audience: account,api://defaultoauth2:# authorization-url: http://localhost:9080/realms/ysn/protocol/openid-connect/authauthorization-url: https://keycloak.scysn.cn/realms/test/protocol/openid-connect/auth

在上述的配置文件中,主要需要配置的就是下面这几个参数:

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
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak
5. 配置 Spring Security

在 Spring Boot 项目中,通过创建一个 SecurityConfig 类来配置安全性:

在这个配置类中主要是配置以下这个bean对象:

@Bean
public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(auth -> auth.requestMatchers(new AntPathRequestMatcher("/customers*", HttpMethod.OPTIONS.name())).permitAll().requestMatchers(new AntPathRequestMatcher("/customers*")).hasRole("user").requestMatchers(new AntPathRequestMatcher("/")).permitAll().anyRequest().authenticated());http.oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));http.oauth2Login(Customizer.withDefaults()).logout(logout -> logout.addLogoutHandler(keycloakLogoutHandler).logoutSuccessUrl("/"));return http.build();
}

在上面的代码中,oauth2Login *()方法将**OAuth2LoginAuthenticationFilter*添加到过滤器链中。该过滤器拦截请求并应用 OAuth 2 身份验证所需的逻辑oauth2ResourceServer方法验证 JWT 令牌与 Keycloak 服务器的绑定。它还强制执行前面讨论的约束。

Keycloak 返回一个包含所有相关信息的令牌。为了使 Spring Security 能够根据用户分配的角色做出决策,我们必须解析令牌并提取相关详细信息。但是 Spring Security 通常在每个角色名称中添加*“ROLES_”前缀,而 Keycloak 则发送纯角色名称。为了解决这个问题,我们创建了一个辅助方法,它为从 Keycloak 检索到的每个角色添加“ROLE_”前缀。*

@Bean
Collection generateAuthoritiesFromClaim(Collection roles) {return roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).collect(Collectors.toList());
}

现在我们可以继续解析令牌了。首先,我们必须检查令牌是否是 OidcUserAuthority 或 OAuth2UserAuthority 的实例。由于 Keycloak 令牌可以是任何一种类型,因此我们需要实现解析逻辑。下面的代码检查令牌的类型并决定解析机制。

boolean isOidc = authority instanceof OidcUserAuthority;if (isOidc) { /// Parsing code here}

默认情况下,令牌是 OidcUserAuthority 的一个实例。

如果令牌是 OidcUserAuthority 实例,则可以将其配置为包含两个组或领域访问下的角色。因此,我们必须检查两者以提取角色,如下面的代码所示,

if (userInfo.hasClaim(REALM_ACCESS_CLAIM)) {var realmAccess = userInfo.getClaimAsMap(REALM_ACCESS_CLAIM);var roles = (Collection) realmAccess.get(ROLES_CLAIM);mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
} else if (userInfo.hasClaim(GROUPS)) {Collection roles = (Collection) userInfo.getClaim(GROUPS);mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
}

但是,如果令牌是 OAuth2UserAuthority 实例,我们需要按如下方式解析它:

var oauth2UserAuthority = (OAuth2UserAuthority) authority;
Map<String, Object> userAttributes 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • SpringBoot的内置缓存以及整合第三方缓存
  • 终端文档安全管理系统是什么?一文给你详解!
  • Spring Boot 3.3 【六】一文读懂 Logback 日志框架
  • 白酒与家庭:团圆时刻的需备佳品
  • 网络攻击常见技术方法(14种)
  • Kotlin学习-01创建kotlin学习环境
  • 程序员如何平衡日常编码工作与提升式学习?
  • RabbitMq实现延迟队列功能
  • 【CSS】使用 CSS 自定义属性(变量)-- var()
  • 基于python的汽车数据分析与可视化---附源码99290
  • 微信小程序详细登录流程
  • Jenkins 2.346.1完整搭建及项目部署安装
  • C语言家教记录(七)
  • 人工智能与机器学习在医学领域的应用
  • 结构型模式之外观模式
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • 2017-09-12 前端日报
  • 30秒的PHP代码片段(1)数组 - Array
  • codis proxy处理流程
  • es6--symbol
  • Javascript基础之Array数组API
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • Vue 动态创建 component
  • web标准化(下)
  • 两列自适应布局方案整理
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 软件开发学习的5大技巧,你知道吗?
  • 试着探索高并发下的系统架构面貌
  • 通过npm或yarn自动生成vue组件
  • 一个JAVA程序员成长之路分享
  • nb
  • elasticsearch-head插件安装
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​zookeeper集群配置与启动
  • # 透过事物看本质的能力怎么培养?
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • ${factoryList }后面有空格不影响
  • (+4)2.2UML建模图
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (备忘)Java Map 遍历
  • (二)JAVA使用POI操作excel
  • (论文阅读40-45)图像描述1
  • (图文详解)小程序AppID申请以及在Hbuilderx中运行
  • (一)Spring Cloud 直击微服务作用、架构应用、hystrix降级
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)负载均衡,回话保持,cookie
  • (转)项目管理杂谈-我所期望的新人
  • ./configure,make,make install的作用(转)
  • .“空心村”成因分析及解决对策122344
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .net core 连接数据库,通过数据库生成Modell
  • .net 后台导出excel ,word
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献