如何将自定义RDBMS作为Keycloak应用领域的用户凭据数据源?
实现方案:自定义Keycloak用户存储Provider
没错,你确实需要自定义Keycloak的用户存储Provider来对接你的自有RDBMS凭据存储。Keycloak默认只认自带数据库或LDAP这类标准数据源,要复用现有凭据库,就得扩展它的用户存储接口。
核心逻辑
通过实现Keycloak的UserStorageProvider相关接口,让Keycloak在验证用户时,调用你编写的代码去自有数据库查询用户、校验密码,无需将凭据迁移到Keycloak的自有库。Keycloak依然负责JWT生成、权限管理等核心功能,仅把用户校验环节委托给自定义Provider。
具体实现步骤
1. 准备项目依赖
创建Maven/Gradle项目,引入与你的Keycloak版本匹配的SPI依赖:
<!-- Maven示例,替换为你的Keycloak版本 --> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-core</artifactId> <version>22.0.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-server-spi</artifactId> <version>22.0.5</version> <scope>provided</scope> </dependency>
2. 实现三个核心接口
(1)Provider工厂类:负责初始化与配置
这是Keycloak加载自定义Provider的入口,同时读取后台配置的数据库连接信息:
public class CustomRDBMSUserProviderFactory implements UserStorageProviderFactory<CustomRDBMSUserProvider> { @Override public CustomRDBMSUserProvider create(KeycloakSession session, ComponentModel model) { // 从Keycloak后台配置中获取数据库连接参数 String jdbcUrl = model.getConfig().getFirst("jdbcUrl"); String dbUser = model.getConfig().getFirst("dbUser"); String dbPwd = model.getConfig().getFirst("dbPassword"); // 初始化自定义数据库操作DAO UserDAO userDAO = new UserDAO(jdbcUrl, dbUser, dbPwd); return new CustomRDBMSUserProvider(session, model, userDAO); } @Override public String getId() { return "custom-rdbms-provider"; // 唯一标识,后台配置时会用到 } // 可选:实现getConfigMetadata()定义后台配置页面的表单字段 }
(2)Provider核心类:处理用户查询与凭据校验
这里是核心业务逻辑,实现用户查询和密码校验方法:
public class CustomRDBMSUserProvider implements UserStorageProvider, CredentialInputValidator { private final KeycloakSession session; private final ComponentModel model; private final UserDAO userDAO; public CustomRDBMSUserProvider(KeycloakSession session, ComponentModel model, UserDAO userDAO) { this.session = session; this.model = model; this.userDAO = userDAO; } // 根据用户名从自有数据库查询用户 @Override public UserModel getUserByUsername(String username, RealmModel realm) { UserEntity user = userDAO.getByUsername(username); if (user == null) return null; // 将自有数据库用户实体转换为Keycloak的UserModel return new UserAdapter(session, realm, model, user); } // 密码校验核心方法 @Override public boolean isValid(RealmModel realm, UserModel user, CredentialInput credentialInput) { // 仅处理密码类型的凭据 if (!CredentialModel.PASSWORD.equals(credentialInput.getType())) { return false; } String inputPwd = credentialInput.getChallengeResponse(); // 调用自定义密码校验逻辑(需与旧系统哈希算法完全一致) return userDAO.verifyPassword(user.getUsername(), inputPwd); } @Override public void close() { // 释放数据库连接等资源 } // 按需实现其他必要方法,比如getUserById、searchForUsers等 }
(3)UserAdapter:转换自有用户到Keycloak模型
Keycloak需要用自身的UserModel处理用户数据,因此需要做实体转换:
public class UserAdapter extends AbstractUserAdapterFederatedStorage { private final UserEntity user; public UserAdapter(KeycloakSession session, RealmModel realm, ComponentModel model, UserEntity user) { super(session, realm, model); this.user = user; } @Override public String getUsername() { return user.getUsername(); } @Override public String getEmail() { return user.getEmail(); } // 按需实现其他UserModel方法,比如getFirstName、getLastName等 }
3. 打包部署
- 将项目打包为JAR包,放入Keycloak的
providers目录 - 重启Keycloak,进入后台管理界面,找到「用户存储」→「添加用户存储」,选择自定义Provider(即工厂类中定义的
custom-rdbms-provider) - 配置数据库连接参数,保存后即可使用自有数据库的用户登录
关键注意事项
- 密码算法必须与旧系统完全一致:如果旧系统使用BCrypt加盐存储,
verifyPassword方法必须用相同算法校验,不能随意更改 - 可添加缓存优化:用户量较大时,实现
UserCacheProvider接口缓存用户信息,减少数据库查询压力 - 角色权限同步:若旧系统有独立角色体系,可在Provider中实现角色映射逻辑,将旧系统角色同步到Keycloak统一管理
内容的提问来源于stack exchange,提问作者Carla
相关产品推荐
相关产品推荐

