获取 Keycloak 的 public 密钥
Getting Keycloak's public key
我意识到这个问题有很多迭代。但我似乎无法正确理解答案。
我们已经使用 oauth2 spring 服务器 similar to this post 保护了我们的 rabbitmq 和 rest 端点。但它不具备我们需要和想要的所有功能。所以我们想使用Keycloak。通过转到新版本 spring security 5.1 并指定 security.oauth2.resource.jwk.key-set-uri 并设置必要的依赖项和配置,我已经成功地保护了其余端点。
在尝试保护 RabbitMQ 时,我 运行 在检查消息 header 中的持有者令牌时遇到了问题,因为 keycloak jwks 端点没有返回真正的 RSA public键。
RabbitMQ 使用 CustomMessageListenerContainer 从消息 header 中获取令牌并使用 DefaultTokenServices 检查令牌。
据我了解,响应密钥的端点是 https://keycloak-server/auth/realms/my-realm/protocol/openid-connect/certs
在此端点上执行 HttpGet,我得到如下所示的响应
{
"keys": [{
"kid": "7JUbcl_96GNk2zNh4MAORuEz3YBuprXilmTXjm0gmRE",
"kty": "RSA",
"alg": "RS256",
"use": "sig",
"n": "nE9gEtzZvV_XisnAY8Hung399hwBM_eykZ9J57euboEsKra8JvDmE6w7SSrk-aTVjdNpjdzOyrFd4V7tFqev1vVJu8MJGIyQlbPv07MTsgYE5EPM4DxdQ7H6_f3vQjq0hznkFvC-hyCqUhxPTXM5NgvH86OekL2C170xnd50RLWw8FbrprP2oRjgBnXMAif1Dd8kwbKKgf5m3Ou0yTVGfsCRG1_LSj6gIEFglxNHvGz0RejoQql0rGMxcW3MzCvc-inF3FCafQTrG5eWHqp5xXEeMHz0JosQ7BcT8MVp9lHT_utiazhQ1uKZEb4uoYOyy6mDDkx-wExpZkOx76bk_Yu-N25ljY18hNllnV_8gVMkX46_vcc-eN3DRZGNJ-Asd_sZrjbXbAvBbKwVxZeOTaXiUdvl8O0G5xX2xPnS_WA_1U4b_V1t28WtnX4bqGlOejW2kkjLvNrpfQ5fnvLjkl9I2B16Mbh9nS0LJD0RR-AkBsv3rKEnMyEkW9UsfgYKLFKuH32x_CXi9uyvNDas_q8WS3QvYwAGEMRO_4uICDAqupCVb1Jcs9dvd1w-tUfj5MQOXB-srnQYf5DbFENTNM1PK390dIjdLJh4k2efCJ21I1kYw2Qr9lHI4X2peTinViaoOykykJiol6LMujUcfqaZ1qPKDy_UnpAwGg9NyFU",
"e": "AQAB"
}
]
}
据我了解,密钥为 "n" 的字段应该是 RSA256 密钥。将其添加到 RSAVerifier 最终会得到 "Caused by: org.springframework.security.jwt.codec.InvalidBase64CharacterException: Bad Base64 input character decimal 95 in array position 2."
的错误
但是,如果我登录到 keycloak 管理页面并进入领域设置-> 密钥并单击 public 键,弹出窗口会显示 public 键减去“---- -BEGIN PUBLIC KEY-----”和“-----END PUBLIC KEY-----”headers 和页脚。硬编码可以使一切正常工作。
密钥是否已编码?
我试过 Base64Utils.decodeFromUrlSafeString 和 Base64Utils.decodeFromString。第一个返回更小的东西并且不像密钥那样看起来,然后创建一个非法参数异常非法 base64 字符 5f。
更新:
返回的 n 是模数,e 是 public 键的 public 指数。但是如何获得实际的密钥字符串呢?
有toIntegerBytes
before base64 encode,所以不只是base64解码。尝试:
BigInteger modulus = new BigInteger(1, Base64.decodeBase64("n-value-here"));
BigInteger exponent = new BigInteger(1, Base64.decodeBase64("e-value-here"));
密钥也直接在 https://keycloak-server/auth/realms/my-realm 上,采用您的代码可直接利用的格式:
{
"realm": "my-realm",
"public_key": "MIIBI...",
"token-service": "https://keycloak-server/auth/realms/my-realm/protocol/openid-connect",
"account-service": "https://keycloak-server/auth/realms/my-realm/account",
"tokens-not-before": 0
}
我也会在以下位置找到它:
- 打开管理控制台
- 选择领域
- 选择领域设置
- 打开标签页 'Keys'
- 打开标签页 'active'
- 在'Public keys'列中按'Public键
- 出现带有 public 键的弹出窗口。
JWKS 端点旨在让它们的密钥随时间变化(在称为 key rotation), so retrieving the public key as per is not a good idea. What you should opt for instead is to use a JWKS client. I use node-jwks-rsa
, but the same creators also have a java implementation (jwks-rsa-java
的过程中)。
我意识到这个问题有很多迭代。但我似乎无法正确理解答案。
我们已经使用 oauth2 spring 服务器 similar to this post 保护了我们的 rabbitmq 和 rest 端点。但它不具备我们需要和想要的所有功能。所以我们想使用Keycloak。通过转到新版本 spring security 5.1 并指定 security.oauth2.resource.jwk.key-set-uri 并设置必要的依赖项和配置,我已经成功地保护了其余端点。
在尝试保护 RabbitMQ 时,我 运行 在检查消息 header 中的持有者令牌时遇到了问题,因为 keycloak jwks 端点没有返回真正的 RSA public键。
RabbitMQ 使用 CustomMessageListenerContainer 从消息 header 中获取令牌并使用 DefaultTokenServices 检查令牌。
据我了解,响应密钥的端点是 https://keycloak-server/auth/realms/my-realm/protocol/openid-connect/certs 在此端点上执行 HttpGet,我得到如下所示的响应
{
"keys": [{
"kid": "7JUbcl_96GNk2zNh4MAORuEz3YBuprXilmTXjm0gmRE",
"kty": "RSA",
"alg": "RS256",
"use": "sig",
"n": "nE9gEtzZvV_XisnAY8Hung399hwBM_eykZ9J57euboEsKra8JvDmE6w7SSrk-aTVjdNpjdzOyrFd4V7tFqev1vVJu8MJGIyQlbPv07MTsgYE5EPM4DxdQ7H6_f3vQjq0hznkFvC-hyCqUhxPTXM5NgvH86OekL2C170xnd50RLWw8FbrprP2oRjgBnXMAif1Dd8kwbKKgf5m3Ou0yTVGfsCRG1_LSj6gIEFglxNHvGz0RejoQql0rGMxcW3MzCvc-inF3FCafQTrG5eWHqp5xXEeMHz0JosQ7BcT8MVp9lHT_utiazhQ1uKZEb4uoYOyy6mDDkx-wExpZkOx76bk_Yu-N25ljY18hNllnV_8gVMkX46_vcc-eN3DRZGNJ-Asd_sZrjbXbAvBbKwVxZeOTaXiUdvl8O0G5xX2xPnS_WA_1U4b_V1t28WtnX4bqGlOejW2kkjLvNrpfQ5fnvLjkl9I2B16Mbh9nS0LJD0RR-AkBsv3rKEnMyEkW9UsfgYKLFKuH32x_CXi9uyvNDas_q8WS3QvYwAGEMRO_4uICDAqupCVb1Jcs9dvd1w-tUfj5MQOXB-srnQYf5DbFENTNM1PK390dIjdLJh4k2efCJ21I1kYw2Qr9lHI4X2peTinViaoOykykJiol6LMujUcfqaZ1qPKDy_UnpAwGg9NyFU",
"e": "AQAB"
}
]
}
据我了解,密钥为 "n" 的字段应该是 RSA256 密钥。将其添加到 RSAVerifier 最终会得到 "Caused by: org.springframework.security.jwt.codec.InvalidBase64CharacterException: Bad Base64 input character decimal 95 in array position 2."
的错误但是,如果我登录到 keycloak 管理页面并进入领域设置-> 密钥并单击 public 键,弹出窗口会显示 public 键减去“---- -BEGIN PUBLIC KEY-----”和“-----END PUBLIC KEY-----”headers 和页脚。硬编码可以使一切正常工作。
密钥是否已编码? 我试过 Base64Utils.decodeFromUrlSafeString 和 Base64Utils.decodeFromString。第一个返回更小的东西并且不像密钥那样看起来,然后创建一个非法参数异常非法 base64 字符 5f。
更新: 返回的 n 是模数,e 是 public 键的 public 指数。但是如何获得实际的密钥字符串呢?
有toIntegerBytes
before base64 encode,所以不只是base64解码。尝试:
BigInteger modulus = new BigInteger(1, Base64.decodeBase64("n-value-here"));
BigInteger exponent = new BigInteger(1, Base64.decodeBase64("e-value-here"));
密钥也直接在 https://keycloak-server/auth/realms/my-realm 上,采用您的代码可直接利用的格式:
{
"realm": "my-realm",
"public_key": "MIIBI...",
"token-service": "https://keycloak-server/auth/realms/my-realm/protocol/openid-connect",
"account-service": "https://keycloak-server/auth/realms/my-realm/account",
"tokens-not-before": 0
}
我也会在以下位置找到它:
- 打开管理控制台
- 选择领域
- 选择领域设置
- 打开标签页 'Keys'
- 打开标签页 'active'
- 在'Public keys'列中按'Public键
- 出现带有 public 键的弹出窗口。
JWKS 端点旨在让它们的密钥随时间变化(在称为 key rotation), so retrieving the public key as per node-jwks-rsa
, but the same creators also have a java implementation (jwks-rsa-java
的过程中)。