如何在Keycloak中设置用户或组级别的会话闲置超时
解决Keycloak组级会话闲置超时覆盖域级配置的方案
针对Keycloak 20.0.1版本,无法修改核心代码的前提下,实现组级属性覆盖域级SSO会话闲置超时,以下是几种可行方案:
方案1:自定义SPI事件监听器(推荐,服务端可靠实现)
Keycloak支持通过SPI扩展功能,无需修改核心代码,仅需编写并部署自定义事件监听器,在会话生命周期中动态调整超时时间:
实现步骤
编写自定义
EventListenerProvider和对应的EventListenerProviderFactory,监听用户会话的创建与更新事件:- 在会话创建(
onSessionCreated)或更新(onSessionUpdated)时,获取当前用户的所有组 - 遍历组属性,提取预设的会话闲置超时值(比如属性名设为
session-idle-timeout,单位分钟) - 取所有组中最小的超时值(若用户属于多组),调用
session.setMaxIdleTime()覆盖会话的闲置超时配置
- 在会话创建(
将编译打包后的jar文件放入Keycloak的
providers目录,执行kc.sh build(Windows下为kc.bat build)重新构建,重启Keycloak在Keycloak控制台的目标域中,进入Events > Config,启用自定义的事件监听器
核心代码示例
@Override public void onSessionCreated(AdminEvent event, UserSessionModel session) { if (session.getUser() == null) return; long effectiveTimeout = -1; List<GroupModel> userGroups = session.getUser().getGroupsStream().collect(Collectors.toList()); for (GroupModel group : userGroups) { String timeoutAttr = group.getAttribute("session-idle-timeout"); if (timeoutAttr == null) continue; try { long timeoutMs = Long.parseLong(timeoutAttr) * 60 * 1000; // 转换为毫秒 if (effectiveTimeout == -1 || timeoutMs < effectiveTimeout) { effectiveTimeout = timeoutMs; } } catch (NumberFormatException ignored) { // 忽略格式错误的属性值 } } if (effectiveTimeout != -1) { session.setMaxIdleTime(effectiveTimeout); } } @Override public void onSessionUpdated(AdminEvent event, UserSessionModel session) { // 会话更新时重新校验组属性,支持动态修改组配置后即时生效 onSessionCreated(event, session); }
方案2:前端主动闲置检测与登出
若不想部署服务端扩展,可在前端实现闲置检测逻辑:
- 监听用户鼠标、键盘等交互事件,记录最后活动时间
- 登录时通过Keycloak的用户属性映射器,将组的超时属性注入ID Token或UserInfo响应中
- 当超出组级闲置时间后,调用Keycloak JS SDK的
logout()方法主动触发登出
注意:该方案依赖前端JS,存在用户禁用JS后的安全风险,仅作为备选方案。
方案3:客户端级超时映射(仅适用于组-客户端一一对应场景)
如果用户组与客户端存在明确的一一对应关系,可:
- 给每个客户端单独配置会话闲置超时
- 通过Keycloak的组-客户端角色映射,限制特定组用户仅能访问对应客户端
- 以此间接实现组级别的超时控制
关键提示
不要尝试修改会话的lastAccessTime属性,Keycloak的会话过期逻辑是基于lastAccessTime + maxIdleTime计算的,修改lastAccessTime到过去无法从根本上覆盖域级超时配置,正确的方式是通过setMaxIdleTime()直接调整会话的闲置超时阈值。
内容的提问来源于stack exchange,提问作者Shubham Khankale
相关产品推荐
相关产品推荐

