Keycloak 18.0.0+版本自定义用户身份提供商的非legacy实现方案咨询
Keycloak 18.0.0+版本自定义用户身份提供商的非legacy实现方案咨询
嗨,针对你升级Keycloak到21.0.0后不想依赖legacy包实现自定义用户身份集成的需求,我给你梳理下官方推荐的两种非legacy方案,你可以根据实际场景选择:
一、针对用户联邦场景(从外部数据源拉取/同步用户):使用拆分后的用户存储SPI
Keycloak 18+把原来单一的UserStorageProvider拆分成了更细粒度的SPI接口,这些接口都在org.keycloak.storage.user包下,完全不属于legacy范畴。你可以按需实现对应的核心接口:
- 仅需根据用户名/邮箱/ID查找用户:实现
UserLookupProvider - 需要支持用户列表查询(分页、过滤):实现
UserQueryProvider - 需要支持用户创建/更新/删除:实现
UserRegistrationProvider - 处理用户凭证(密码、OTP等):实现
UserCredentialManagerProvider
简单实现示例
- 实现
UserLookupProvider核心逻辑:
public class CustomUserLookupProvider implements UserLookupProvider { private final KeycloakSession session; private final ComponentModel model; // 构造方法注入会话和配置模型 public CustomUserLookupProvider(KeycloakSession session, ComponentModel model) { this.session = session; this.model = model; } @Override public UserModel getUserByUsername(String username, RealmModel realm) { // 替换为你的自定义数据源查询逻辑,比如从数据库/API拉取用户 UserModel user = session.userLocalStorage().addUser(realm, username); user.setEmail(username + "@yourdomain.com"); user.setFirstName("Custom"); user.setLastName("User"); return user; } @Override public UserModel getUserByEmail(String email, RealmModel realm) { // 实现邮箱查找逻辑 return null; } @Override public UserModel getUserById(String id, RealmModel realm) { // 实现ID查找逻辑 return null; } }
- 实现对应的工厂类(用于注册和创建Provider实例):
public class CustomUserLookupProviderFactory implements UserStorageProviderFactory<CustomUserLookupProvider> { @Override public CustomUserLookupProvider create(KeycloakSession session, ComponentModel model) { return new CustomUserLookupProvider(session, model); } // 定义Provider的唯一ID,后台配置时会显示 @Override public String getId() { return "custom-user-lookup-provider"; } // 后台配置时显示的帮助文本 @Override public String getHelpText() { return "自定义用户查找Provider,从外部数据源拉取用户信息"; } // 可选:添加配置项,比如数据源地址、认证信息等 @Override public List<ProviderConfigProperty> getConfigProperties() { List<ProviderConfigProperty> properties = new ArrayList<>(); properties.add(new ProviderConfigProperty( "data-source-url", "数据源地址", "外部用户数据源的API地址或JDBC URL", ProviderConfigProperty.STRING_TYPE, null )); return properties; } }
- 注册Provider:在项目的
META-INF/services目录下创建org.keycloak.storage.UserStorageProviderFactory文件,写入你的工厂类全限定名,比如:
com.yourcompany.keycloak.provider.CustomUserLookupProviderFactory
完成后,你就能在Keycloak后台的User Federation菜单里找到这个自定义Provider,配置后即可使用。
二、针对身份认证集成场景(对接外部SSO/身份系统):使用Identity Provider SPI
如果你的需求是让用户通过外部自定义身份系统登录Keycloak(比如企业内部的SSO),更推荐使用Keycloak的Identity Provider SPI,这是完全独立于legacy的方案,核心接口在org.keycloak.broker.provider包下。
核心步骤:
- 实现
IdentityProvider接口,或者继承抽象类AbstractIdentityProvider(简化开发) - 实现
IdentityProviderFactory来创建Provider实例,并注册到META-INF/services/org.keycloak.broker.provider.IdentityProviderFactory
这种方案的优势是完全贴合Keycloak的身份认证流程,支持OAuth2、SAML之外的自定义认证协议,不需要处理用户存储的细节,只需要负责身份断言的转换。
总结
- 若要从外部数据源拉取/管理用户:选择拆分后的用户存储SPI,避免使用legacy包的
UserStorageProvider - 若要对接外部身份认证系统:选择Identity Provider SPI,这是官方推荐的身份集成方案
备注:内容来源于stack exchange,提问作者Djordje




