Keycloak 25:自定义UserStorageProvider区分IdP与用户名登录查询逻辑
Keycloak自定义用户存储提供者与身份提供者登录逻辑适配问题
问题背景
使用Keycloak 25,实现了自定义用户存储提供者:
CustomerStorageProvider implements UserStorageProvider, UserLookupProvider, CredentialInputValidator, CredentialInputUpdater
该提供者的getUserById和getUserByUsername方法通过外部API,以用户名为条件查询用户信息。
期望效果:
- 普通登录:保留现有逻辑,用用户名查询
- IdP登录:调用另一外部API,以IdP返回
userinfo中的声明(claim)为查询条件,而非用户名
已尝试操作:
在自定义认证流程中添加自定义步骤,并关联到IdP的First Broker Login Flow,首次登录时可通过IdP声明调用备选API,且因联邦用户不存在,流程正常执行。
遇到的问题:
首次登录后,Keycloak存储了联邦用户,其storageId指向自定义提供者;后续IdP登录时,Keycloak会通过该提供者解析用户,触发getUserById/getUserByUsername方法,仍以用户名查询,不符合需求。
问题解答
1. 如何检测当前登录是通过身份提供者(IdP)发起的(首次登录之后)?
可以通过KeycloakSession获取当前的AuthenticationSessionModel,检查其中的身份提供者相关标识:
AuthenticationSessionModel authSession = session.getContext().getAuthenticationSession(); if (authSession != null && authSession.getAuthNote(IdentityBrokerConstants.IDENTITY_PROVIDER) != null) { // 当前为IdP发起的登录 }
也可通过以下方式辅助判断:
- 检查
authSession.getClientNote(IdentityBrokerConstants.FEDERATED_IDENTITY)是否存在 - 验证当前执行的认证流程是否属于Broker相关流程(如
authSession.getAuthenticationFlowId()是否匹配First/Post Broker Login Flow的ID)
2. 如何覆盖或绕过默认的UserStorageProvider查询逻辑,使用IdP的声明调用外部API?
推荐以下几种方案:
方案一:增强自定义UserStorageProvider逻辑
在现有提供者中注入KeycloakSession,在查询方法中判断登录来源,切换查询逻辑:
public class CustomerStorageProvider implements UserStorageProvider, UserLookupProvider, ... { private final KeycloakSession session; public CustomerStorageProvider(KeycloakSession session, Config.Scope config) { this.session = session; } @Override public UserModel getUserByUsername(String username, RealmModel realm) { AuthenticationSessionModel authSession = session.getContext().getAuthenticationSession(); if (authSession != null && authSession.getAuthNote(IdentityBrokerConstants.IDENTITY_PROVIDER) != null) { // 从authSession中获取预先存储的IdP claim String idpClaim = authSession.getUserSessionNote("target_idp_claim"); // 调用备选API查询用户 return fetchUserFromAlternativeApi(idpClaim, realm); } // 普通登录逻辑:用用户名查询 return fetchUserFromDefaultApi(username, realm); } }
注意:需在IdP登录流程的自定义步骤中,将所需claim存入
authSession:authSession.setUserSessionNote("target_idp_claim", userinfo.getClaim("your_claim_key"));
方案二:扩展Post Broker Login流程
不依赖UserStorageProvider的自动解析,在Post Broker Login Flow中添加自定义认证器:
- 在自定义认证器中检测是否为IdP登录
- 直接使用
userinfo中的claim调用备选API获取用户信息 - 同步或关联Keycloak中的联邦用户,确保后续登录时使用该逻辑
此方案可完全控制IdP登录的用户查询流程,避免触发默认的UserStorageProvider查询。
方案三:自定义FederatedIdentityMapper SPI
实现FederatedIdentityMapper接口,在联邦身份映射阶段处理用户查询逻辑:
- 在
updateBrokeredUser方法中,使用IdP的claim调用备选API获取用户信息 - 调整用户的存储关联或属性,确保后续登录时使用正确的查询逻辑
推荐扩展点
- 自定义认证器(Authenticator SPI):适合在Broker登录流程中插入自定义逻辑,完全控制IdP登录的用户处理路径
- 增强
UserStorageProvider:适合复用现有存储提供者,仅需添加上下文判断和分支逻辑 - FederatedIdentityMapper SPI:适合在联邦身份映射环节处理用户关联与信息同步
内容的提问来源于stack exchange,提问作者user1609
相关产品推荐
相关产品推荐

