Keycloak获取新令牌时未关闭旧会话的解决方案咨询
Keycloak 19.0.0 密码授权模式下自动关闭旧会话的实现方案
核心思路
Keycloak原生未提供密码授权时自动清理旧会话的功能,需通过扩展认证流程或自定义服务实现,以下是几种可行的开发方法:
方法一:自定义认证器(Authenticator)扩展
- 编写自定义Authenticator
- 实现
org.keycloak.authentication.Authenticator接口,在authenticate方法中加入清理旧会话的逻辑:- 通过
session.sessions().getUserSessions(realm, user)获取当前用户的所有活跃会话 - 遍历会话列表,排除当前正在创建的会话(可通过会话ID或请求上下文判断),调用
session.sessions().removeUserSession(realm, oldSession)删除旧会话
- 通过
- 实现
- 注册与配置
- 将Authenticator打包为JAR,放入Keycloak的
providers目录 - 重启Keycloak后,在目标Realm的认证流程中,将自定义Authenticator添加到密码验证节点之后
- 将Authenticator打包为JAR,放入Keycloak的
方法二:Token Endpoint拦截器扩展
- 实现TokenEndpoint SPI
- 扩展
org.keycloak.protocol.oidc.endpoints.TokenEndpoint,重写grantPasswordCredentials方法 - 生成新令牌前,先清理用户旧会话:
UserModel user = session.users().getUserByUsername(username, realm); List<UserSessionModel> oldSessions = session.sessions().getUserSessions(realm, user); for (UserSessionModel oldSession : oldSessions) { if (!oldSession.getId().equals(session.getContext().getUserSession().getId())) { session.sessions().removeUserSession(realm, oldSession); } } - 注意同步清理关联的客户端会话
- 扩展
- 注册扩展
- 在
META-INF/services目录创建org.keycloak.protocol.oidc.endpoints.TokenEndpoint文件,写入自定义实现类的全路径 - 打包JAR放入Keycloak providers目录,重启生效
- 在
方法三:客户端配合Admin API实现
若不想修改Keycloak源码,可在调用令牌接口的客户端代码中添加逻辑:
- 获取新令牌前,调用Admin API的
GET /admin/realms/{realm}/users/{user-id}/sessions获取用户所有活跃会话 - 遍历会话列表,调用
DELETE /admin/realms/{realm}/user-sessions/{session-id}删除旧会话 - 再调用密码授权接口获取新令牌
- 注意:客户端需拥有
manage-users、manage-sessions等权限,且需先获取Admin API的服务账户令牌
注意事项
- 所有方法需注意避免误删当前正在创建的会话,影响新令牌生成
- 验证旧会话删除后,对应的旧访问令牌、刷新令牌是否失效(Keycloak默认删除会话后令牌会失效)
- 自定义扩展需适配Keycloak 19.0.0的API版本,避免兼容性问题
内容的提问来源于stack exchange,提问作者kernel
相关产品推荐
相关产品推荐

