如何在Keycloak协议映射器中从自定义认证器获取数据?
问题分析与解决方案
你遇到的核心问题是会话作用域不匹配:在自定义认证器中把数据存在了请求级的KeycloakSession,而这个会话在认证流程结束后就会被销毁;协议映射器运行时依赖的是用户持久会话UserSessionModel,自然拿不到之前存储的数据。
一、修改自定义认证器:将数据存入用户持久会话
把数据从KeycloakSession转移到UserSessionModel中,后者是跨请求的用户级会话,会伴随用户登录状态保留。
修改后的MyCustomAuthenticator代码:
public class MyCustomAuthenticator extends UsernamePasswordForm { @Override public boolean validatePassword(final AuthenticationFlowContext context, final UserModel user, final MultivaluedMap<String, String> inputData, final boolean clearUser) { // 获取用户持久会话并设置属性 context.getAuthenticationSession().getParentSession().setAttribute("data", "test"); // 必须调用父类方法或返回正确布尔值,否则认证流程会中断 return super.validatePassword(context, user, inputData, clearUser); } }
二、修改协议映射器:从用户持久会话中读取数据
在映射器中直接从传入的UserSessionModel对象获取属性,再写入Token的Claim中。
修改后的RmDataTokenMapper代码:
public class RmDataTokenMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper { @Override protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession keycloakSession, ClientSessionContext clientSessionCtx) { // 从用户持久会话中读取属性 String data = (String) userSession.getAttribute("data"); // 将属性写入Token的自定义Claim(示例中用"custom_data"作为Claim名) token.getOtherClaims().put("custom_data", data); } }
关键说明
KeycloakSession是请求作用域:每个请求都会创建新实例,认证流程完成后立即销毁,无法跨请求共享数据。UserSessionModel是用户会话作用域:只要用户处于登录状态,该会话就会保留,所有与该用户相关的请求都能访问其中的属性。- 若需存储复杂对象,确保对象可序列化(
UserSession的属性会被Keycloak持久化或序列化传输)。
内容的提问来源于stack exchange,提问作者Piyush Chaudhari
相关产品推荐
相关产品推荐

