两个 keycloak 服务器之间的身份提供者

问题描述 投票:0回答:1

我有以下场景: 钥匙斗篷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 中我创建了一个客户端并放置了

访问类型:机密

有效的重定向 URIhttp://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

我忘记做什么?

java spring-boot jwt keycloak openid-connect
1个回答
2
投票

每个 Keycloak 实例(或领域)都有自己的一组用于签署 JWT 的密钥,并且每个密钥都可以按照自己的节奏轮换(是的,密钥对应该在运行时更改,并且 JWT 解码器应该在它们使用新的公钥时获取新的公钥) had 已弃用)。

即使 Keycloak A 在 Keycloak B 中注册为联合身份提供者,您也无法使用 Keycloak B 中的密钥来验证 Keycloak A 颁发的令牌。当用户在 Keycloak B 上进行身份验证时选择“使用 Keycloak A 登录”时,客户端收到的令牌由 Keycloak B 发出。

据我了解,您的 Spring 应用程序是资源服务器(它通过访问令牌进行保护)。

Spring boot 默认配置是单租户(接受来自单个颁发者的身份)。要改变这一点,您必须:

  • 实例化两个不同的 JWT 解码器(一个用于 Keycloak A 发行者,另一个用于 Keycloak A 发行者) 对于 Keycloak B 发行人)
  • 提供自定义身份验证管理器,该管理器根据
    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 等)。

© www.soinside.com 2019 - 2024. All rights reserved.