我有以下场景: 钥匙斗篷A 钥匙斗篷B
Keycloak A 正在 Spring Boot 应用程序中用于身份验证。
Keycloak B 正在 Spring Boot 应用程序中用于身份验证。
我希望 Keycloak A 的用户 (JWT) 能够访问由 keycloak B 管理的应用程序的端点。
我做了什么但没有成功: 在 keycloak B 中,我创建了一个身份提供者。 http://localhost:8083/auth/realms/master/broker/oidc/endpoint
我添加了带有 keycloak A 数据的字段:
授权网址
代币网址
客户端身份验证:客户端密钥以帖子形式发送
客户ID
客户秘密
在 keycloak A 中我创建了一个客户端并放置了
访问类型:机密
有效的重定向 URI:http://localhost:8083/auth/realms/master/broker/keycloak-oidc/endpoint
在 Credential 中,我放置了 Client Authenticator 并生成了密钥。
当我在 keycloak A 中生成令牌并尝试访问 keycloak B 中的应用程序的端点时,它会生成以下错误:
Signed JWT rejected: Another algorithm expected, or no matching key(s) found
我忘记做什么?
每个 Keycloak 实例(或领域)都有自己的一组用于签署 JWT 的密钥,并且每个密钥都可以按照自己的节奏轮换(是的,密钥对应该在运行时更改,并且 JWT 解码器应该在它们使用新的公钥时获取新的公钥) had 已弃用)。
即使 Keycloak A 在 Keycloak B 中注册为联合身份提供者,您也无法使用 Keycloak B 中的密钥来验证 Keycloak A 颁发的令牌。当用户在 Keycloak B 上进行身份验证时选择“使用 Keycloak A 登录”时,客户端收到的令牌由 Keycloak B 发出。
据我了解,您的 Spring 应用程序是资源服务器(它通过访问令牌进行保护)。
Spring boot 默认配置是单租户(接受来自单个颁发者的身份)。要改变这一点,您必须:
iss
声明委托给正确的解码器(Keycloak A 和 Keycloak B 不会在它们发出的令牌中放入相同的值)在
我的这个教程中仅使用
spring-boot-starter-oauth2-resource-server
即可完成示例。但是你可以使用 spring-addons-starter-oidc
(我的一个状态器,它位于 Spring Boot“官方”启动器之上)来实现相同的目标,而根本不需要 Java conf:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-starter-oidc</artifactId>
<version>7.0.0</version>
</dependency>
# spring.security.oauth2.resourceserver properties fit only to single tenant scenarios (only one issuer). It is not used here.
keycloak-a: http://localhost:8442/realms/a
keycloak-b: http://localhost:8442/realms/b
com:
c4-soft:
springaddons:
oidc:
ops:
- iss: ${keycloak-a}
username-claim: preferred_username
authorities:
# map realm roles to spring authorities (you might add a prefix or case transformation with dedicated properties)
- path: $.realm_access.roles
# map roles for all clients, you might want to restrict to a single client or two
- path: $.resource_access.*.roles
- iss: ${keycloak-b}
username-claim: preferred_username
authorities:
- path: $.realm_access.roles
- path: $.resource_access.*.roles
resourceserver:
# What is not listed in "permit-all" requires request to be authorized
# Fine-tuned access-control with method security ("@preAuthorize" and alike) or a by exposing a ResourceServerExpressionInterceptUrlRegistryPostProcessor bean
permit-all:
- "/actuator/health/readiness"
- "/actuator/health/liveness"
- "/v3/api-docs/**"
@Configuration
@EnableMethodSecurity()
public class SecurityConfig {
}
很不错,不是吗?
最好的部分是,您的代码中没有任何特定于 Keycloak 的内容,只需编辑权限和用户名映射的属性,即可将任何发行者切换到您喜欢的任何 OIDC 授权服务器(Auth0、Cognito 等)。