默认情况下,同意令牌和脱机令牌与客户端和当前登录的User
相关联。
我们应用的客户是公司。脱机令牌表示公司之间的关系。当前登录的用户只是具有相关权限的代理,可以建立此关系。因此,当合作伙伴客户使用身份验证代码流请求脱机令牌时,我们希望将脱机令牌发布给代表当前用户雇主(即该用户为其工作的公司)而不是当前登录用户的“用户”。
动机:我们要避免当用户不可避免地辞职时删除用户时,脱机令牌会失效,并且我们可以通过GET /{realm}/users/{id}/consents
通过一次API调用获得公司的所有同意,所以我们不这样做不必查询每位员工的同意就可以了解全部情况。
但是,当雇员登录后,如何获得为雇主发行的脱机令牌?
我尝试在Keycloak Discourse上问一个不太详细的问题。到目前为止,还没有答案。
因此,现在我正在使用身份验证SPI在员工登录后,在身份验证过程结束时创建Authenticator
,我们将完成身份验证。在public void authenticate(AuthenticationFlowContext context) {}
中,我可以看到上下文以及当前登录的员工用户。
为简单起见,如果客户ID为“ PartnerCompany”,我想将用户更改为“ acme”。
从context.getAuthenticationSession()
中我可以得到一个AuthenticationSessionModel
,上面有此评论(重新包装):
/**
* Represents the state of the authentication. If the login is requested
* from different tabs of same browser, every browser tab has it's own
* state of the authentication.
* So there is separate AuthenticationSessionModel for every tab. Whole browser
* is represented by {@link RootAuthenticationSessionModel}
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
AuthenticationSessionModel
有一个方法:
void setAuthenticatedUser(UserModel user)
所以我以为我很黄金!我只能为此标签设置用户。我的计划基本上是在authenticate()
中做到这一点:
AuthenticationSessionModel authSession = context.getAuthenticationSession();
if (authSession.getClient().getClientId().equals("PartnerCompany")) {
UserModel user = context.getSession().users().getUserByUsername("acme", realm);
if (user == null)
throw new RuntimeException("No user acme");
logger.warn("Setting user to " + user.getUsername());
authSession.setAuthenticatedUser(user);
}
那没有达到我的预期。如果SSO会话已经处于活动状态,我会看到一条日志消息Setting user to acme
,但是令牌中的用户仍然是登录用户,而不是acme。如果没有活动的SSO会话,则将令牌发布给“ acme”,SSO变为活动状态,并且SSO会话中的所有客户端均以用户“ acme”的身份登录:-(
我还尝试了context.fork()
,context.clearUser()
,context.setUser(user)
的各种组合,或者用户未更改令牌,或者用户在SSO会话和令牌。但是我只想更改令牌和注册同意书中的用户,而不是SSO会话。
当然,我们可以实现一个非标准的终结点,该终结点进行某种形式的令牌交换:给定 employee 的令牌,它返回 employer 的令牌>但这并不那么优雅。
有什么办法可以更改用户仅用于此客户端,以便为用户“ acme”注册同意书,并为用户“ acme”注册脱机令牌,但是SSO会话仍保留为原始员工用户吗?