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

Keycloak 20.0.5:自定义认证器向事件监听器传值失败排查

问题根源及解决方案

1. 请求作用域Session属性丢失

你在认证器中通过session.setAttribute("attr", "9")设置的是请求作用域的KeycloakSession属性,该属性仅绑定当前认证请求的线程(日志显示认证器运行在executor-thread-5,事件监听器在executor-thread-8)。认证流程结束后,请求上下文销毁,属性无法在后续事件监听器中获取。

修复方案:
若需传递数据到事件监听器,放弃请求作用域属性,改用以下两种方式:

  • 将数据写入用户会话笔记(UserSessionNote)
  • 直接添加到认证事件的详情中:
// 认证器中添加
context.getEvent().detail("custom_attr", "9");

之后在事件监听器中通过event.getDetails().get("custom_attr")读取。

2. AuthNote仅存在于认证流程期间

setAuthNote设置的是AuthenticationSession的临时笔记,仅在认证流程进行中有效。认证成功完成后,AuthenticationSession会被转换为UserSession或销毁,事件监听器触发时已无法访问原会话,因此获取不到值。

修复方案:
如果需要数据持久化到用户会话,改用setUserSessionNote;如果仅需在事件中携带数据,直接写入事件详情(如上述方法)。

3. UserSessionNote获取方式错误

你在认证器中调用了setUserSessionNote,但事件监听器中通过session.getContext().getAuthenticationSession()获取的并非已完成认证的会话对象(该上下文在登录完成后已失效)。正确做法是通过事件中的会话ID获取实际的UserSession。

修复方案:
修改事件监听器中获取UserSessionNote的代码:

// 事件监听器onEvent方法内
RealmModel realm = this.model.getRealm(event.getRealmId());
UserSessionModel userSession = this.session.sessions().getUserSession(realm, event.getSessionId());
if (userSession != null) {
    String sn = userSession.getNotes().get("sess_note");
    log.debugf("sess_note: %s", sn);
}

4. 日志格式化错误

你的日志语句log.debugf("auth_note: ", an)缺少格式化占位符%s,即使值不为null也无法正确打印。

修复方案:
修正所有日志格式化语句:

log.debugf("session: %s", a.toString());
log.debugf("auth_note: %s", an);
log.debugf("sess_note: %s", sn);

调整后的关键代码示例

认证器代码(核心修改)

@Override
public void authenticate(AuthenticationFlowContext context) {
    // ... 原有代码 ...
    
    // 将数据写入事件详情
    context.getEvent().detail("auth_note", "8");
    
    // 设置UserSessionNote(将同步到最终UserSession)
    context.getAuthenticationSession().setUserSessionNote("sess_note", "7");
    
    context.success();
}

事件监听器代码(核心修改)

@Override
public void onEvent(Event event) {
    // ... 原有代码 ...
    
    // 从事件详情读取auth_note
    String an = event.getDetails().get("auth_note");
    log.debugf("auth_note: %s", an);
    
    // 从UserSession读取sess_note
    RealmModel realm = this.model.getRealm(event.getRealmId());
    UserSessionModel userSession = this.session.sessions().getUserSession(realm, event.getSessionId());
    if (userSession != null) {
        String sn = userSession.getNotes().get("sess_note");
        log.debugf("sess_note: %s", sn);
    }
    
    // ... 原有代码 ...
}

内容的提问来源于stack exchange,提问作者Adam Muller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 08:15:58