【发布时间】:2020-02-08 19:02:09
【问题描述】:
我有一个由 Keycloak 保护的多租户应用程序(springboot keycloak 适配器 + spring security)。鉴于项目的多租户性质,我编写了一个运行良好的多客户端连接器。
在官方 Keycloak 文档中,建议(对于多租户应用程序)将每个租户建模为一个新领域,但对我来说,在同一领域内拥有多个客户端会更好。这是由于以下优点:
- 可以共享客户端范围、组和其他配置
- 用户无需在 N 个不同领域重复
- SSO 登录在同一领域客户端中完美运行(通过使用承载 服务 +CORS)
所以,除了一件事,我的初始 SSO access_token(然后通过 CORS 在所有仅承载服务之间共享)有点大(它显示了所有资源 - 租户 - 及其每个资源/租户中的角色)。
我想限制access_token 的大小,方法是使用“范围”将令牌中的角色限制为仅对我当时登录的租户有意义的角色。为此,我手动向身份验证服务器发出请求(在 springboot/spring security 提供的标准功能之外),目的是手动覆盖我的应用程序中存在的任何访问令牌,新的访问令牌由我的额外生成请求。
我的“新”令牌请求如下所示:
SimpleKeycloakAccount currentUserAccount = (SimpleKeycloakAccount) auth.getDetails();
String authServerUrl = currentUserAccount.getKeycloakSecurityContext().getDeployment().getAuthServerBaseUrl();
String realm = currentUserAccount.getKeycloakSecurityContext().getDeployment().getRealm();
String resource = currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceName();
String refreshToken = currentUserAccount.getKeycloakSecurityContext().getRefreshToken();
String token = currentUserAccount.getKeycloakSecurityContext().getTokenString();
Http http = new Http( new Configuration(authServerUrl, realm, resource,
currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceCredentials()
, null),
(params, headers) -> {});
String url = authServerUrl + "/realms/" + realm + "/protocol/openid-connect/token";
AccessTokenResponse response = http.<AccessTokenResponse>post(url)
.authentication()
.client()
.form()
.param("grant_type", "refresh_token")
.param("refresh_token", refreshToken)
.param("client_id", resource)
.param("client_secret", "SOME_SECRET")
.param("scope", "SOME_SCOPE_TO_RESTRICT_ROLES")
.response()
.json(AccessTokenResponse.class)
.execute();
// :) - response.getToken() and response.getRefreshToken(), contain new successfully generated tokens
我的问题是,如何使用这些“自定义创建”令牌强制 my-app 更改/重置通过通常方式获得的标准 access-token 和 refresh_token?还是有可能?
感谢任何反馈!
更多信息
为了澄清更多,让我们分析一个典型的与 Keycloak 集成的 springboot/spring 安全项目的行为:
- 您可以通过配置(在 application.properties 或 SecurityContext 上)使用“角色”保护您的端点
- 你知道这个 Spring 应用程序在后台通道中与 Keycloak 授权服务器对话,这就是你成为 access_token 的方式(但这对开发人员来说是一个黑盒子,你只知道创建了一个 Principal,一个 Security Context,凭证;等等 - 一切都发生在幕后)
考虑到上述两点,假设您使用 Http 库基本上向身份验证服务器令牌端点请求一个新令牌,就像上面的代码一样(是的,按范围和所有内容过滤)。所以现在的情况是,虽然你已经创建了一个有效的access_token(和refresh_token);由于它们是通过向令牌端点发出请求“手动”创建的,因此该新令牌尚未“合并”到应用程序中,因为没有创建新的主体,没有生成新的安全上下文等。换句话说,对于 springboot 应用程序来说,这个新令牌是不存在的。
我想要完成的是告诉 sprinboot/spring security:“嘿,朋友,我知道你没有自己生成这个令牌,但请接受它并表现得好像你已经创建了它一样”。
我希望这能澄清我的问题的意图。
【问题讨论】:
-
由于您的客户端应用程序拥有的令牌现在无效,这不会在第一次请求时自动发生吗?
-
原始令牌不会因为发出新的令牌请求而失效。不,应用程序完全忽略了新的令牌,并且只会在 5 分钟(通常是 5 分钟)后变为无效时像在任何其他应用程序中一样刷新。
-
@Eugen Covaci 假设您有一个有效的令牌,然后您“刷新它”,这不会使原始令牌无效。原版过期或被明确撤销时失效。
-
@tony_008 登录时如何确定租户?这些信息存储在 keycloak 中的什么位置?
-
@Boomer,每个租户只是一个标准的 keycloak 客户端。我有一个“主后端”,它也是一个 Keycloack 客户端。通过令牌元数据,我收到用户所在的租户。从那里只有承载的“多租户端点”,需要定制的多租户连接器,这不是开箱即用的。具体来说,您需要扩展“KeycloakSpringBootConfigResolver 实现 KeycloakConfigResolver”,其中可以对方法“createDeploymentJSON(AccessToken accessToken, String tennantNo)”进行参数化以使用不同的配置;以及 SecurityConfig "KeycloakConfigResolver"
标签: spring-boot spring-security oauth-2.0 keycloak