You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Keycloak始终存储Broker Context并在登录后流程中传递给自定义SPI

如何让Keycloak始终存储Broker Context并在登录后流程中传递给自定义SPI

我之前在做Keycloak SAML集成时也碰到过一模一样的问题——首次登录时能顺利拿到Broker Context,但后续登录的post-login流程里就拿不到了。后来才搞明白,Keycloak默认只会在用户首次关联身份提供商(IdP)的时候保留这个上下文,之后直接复用已有的用户会话,不会再把Broker Context存入认证会话的notes里。这里给你几个实用的解决思路,你可以根据自己的场景选:

方法1:把Broker Context持久化到用户属性中

既然首次登录时你能正常拿到Broker Context,那不如直接把它存在用户的自定义属性里,这样不管是首次还是后续登录,都能从用户属性里读取到。

在你SPI的首次登录逻辑里添加存储代码:

// 首次登录时获取Broker Context并存入用户属性
String brokerContextData = context.getAuthenticationSession().getAuthNote(AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
UserModel user = context.getAuthenticationSession().getAuthenticatedUser();
if (brokerContextData != null && user.getFirstAttribute("broker_context") == null) {
    // 若上下文是字符串格式可直接存储,复杂结构可以先序列化
    user.setSingleAttribute("broker_context", brokerContextData);
    // 别忘了更新用户信息到Keycloak
    UserManager userManager = new UserManager(context.getSession());
    userManager.updateUser(context.getRealm(), user);
}

之后在post-login流程里,直接从当前用户的属性中读取:

UserModel user = context.getUserSession().getUser();
String brokerContextData = user.getFirstAttribute("broker_context");
if (brokerContextData != null) {
    // 执行你的用户属性清理逻辑
}

这个方法的好处是一劳永逸,存一次之后每次都能拿到,适合Broker Context不会频繁变化的场景。

方法2:在Broker登录阶段手动复制到UserSession属性

如果你的Broker Context每次登录都可能有变化,不适合存在用户属性里,那可以把它复制到UserSession的属性中——UserSession在整个登录会话周期内都是有效的,post-login流程也能轻松访问到。

在你SPI的认证方法里(比如authenticate阶段),拿到Broker Context后存入UserSession:

String brokerContextData = context.getAuthenticationSession().getAuthNote(AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
if (brokerContextData != null) {
    // 存入UserSession的自定义属性
    context.getAuthenticationSession().getUserSession().setAttribute("CUSTOM_BROKER_CONTEXT", brokerContextData);
}

然后在post-login的SPI实现里读取:

String brokerContextData = (String) context.getUserSession().getAttribute("CUSTOM_BROKER_CONTEXT");
if (brokerContextData != null) {
    // 执行你的业务逻辑
}

注意Keycloak的UserSession属性会跟着会话走,会话过期后就会消失,适合每次登录都需要最新Broker Context的场景。

方法3:扩展IdP认证器,强制每次登录都存入Broker Context

如果上面的方法都不符合你的需求,你可以自定义一个继承自AbstractIdpAuthenticator的认证器,重写它的action方法,在每次处理SAML断言后,手动把Broker Context存入认证会话的notes里,这样post-login流程就能像首次登录一样拿到它。

示例代码大概是这样:

public class CustomSamlIdpAuthenticator extends SamlIdpAuthenticator {

    @Override
    public void action(AuthenticationFlowContext context) {
        // 先执行父类的逻辑,处理SAML断言
        super.action(context);
        
        // 从当前的IdP响应中提取Broker Context
        BrokeredIdentityContext brokeredContext = getBrokeredIdentityContext(context);
        if (brokeredContext != null) {
            // 把Broker Context序列化成字符串,存入认证会话的note
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                String contextJson = objectMapper.writeValueAsString(brokeredContext);
                context.getAuthenticationSession().setAuthNote(AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE, contextJson);
            } catch (JsonProcessingException e) {
                // 处理序列化异常
                throw new RuntimeException("Failed to serialize broker context", e);
            }
        }
    }
}

然后你需要在Keycloak里配置使用这个自定义的认证器,替换掉默认的SAML IdP认证器。这个方法最灵活,但需要你对Keycloak的认证流程有一定了解。

总的来说,最推荐的是方法1或方法2,根据你的Broker Context是否需要动态更新来选择,方法3适合有特殊定制需求的场景。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 12:44:30