如何让Keycloak外部用户存储使用内部数据库凭证进行认证?
实现Keycloak外部用户使用内部凭证表认证的方案
核心思路
让你的自定义UserStorageProvider实现CredentialInputValidator和CredentialInputUpdater接口,但完全委托Keycloak内部的UserCredentialManager处理凭证逻辑,不依赖外部存储的凭证数据,仅从外部存储获取用户基础信息(ID、用户名、邮箱)。
具体实现步骤
1. 注入KeycloakSession
在自定义Provider的构造方法中注入KeycloakSession,用于获取内部凭证管理工具:
private final KeycloakSession session; public CustomUserStorageProvider(KeycloakSession session, ComponentModel model) { this.session = session; // 其他外部存储初始化逻辑 }
2. 实现CredentialInputValidator接口
该接口负责凭证验证,所有逻辑委托给Keycloak内部机制:
@Override public boolean supportsCredentialType(String credentialType) { // 仅支持Keycloak默认密码凭证类型 return PasswordCredentialModel.TYPE.equals(credentialType); } @Override public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) { // 检查Keycloak内部是否已为该用户配置凭证 return session.userCredentialManager().isConfiguredFor(realm, user, credentialType); } @Override public boolean validateCredential(RealmModel realm, UserModel user, CredentialInput input) { if (!supportsCredentialType(input.getType())) { return false; } // 委托Keycloak到内部credential表验证凭证 return session.userCredentialManager().validateCredential(realm, user, input); }
3. 实现CredentialInputUpdater接口
该接口负责凭证更新/删除,同样委托给内部管理工具:
@Override public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) { if (!supportsCredentialType(input.getType())) { return false; } // 让Keycloak将新凭证存储到内部表 return session.userCredentialManager().updateCredential(realm, user, input); } @Override public void deleteCredential(RealmModel realm, UserModel user, String credentialType) { // 删除Keycloak内部存储的该用户凭证 session.userCredentialManager().deleteCredential(realm, user, credentialType); } // supportsCredentialType和isConfiguredFor方法可直接复用上面的实现
4. 关联外部用户ID与内部凭证
确保从外部存储加载用户时,返回的UserModel的getId()方法返回外部存储的用户唯一ID——Keycloak的内部credential表会通过这个ID关联用户凭证,保证凭证与外部用户的对应关系。
5. 同步用户删除操作
当从外部存储删除用户时,同时清理Keycloak内部的凭证记录:
@Override public boolean removeUser(RealmModel realm, UserModel user) { // 先删除外部存储的用户 boolean externalDeleteSuccess = yourExternalStorageClient.deleteUser(user.getId()); if (externalDeleteSuccess) { // 清理Keycloak内部的该用户所有凭证 session.userCredentialManager().deleteCredentials(realm, user); } return externalDeleteSuccess; }
测试流程
- 在外部存储创建用户(如ID:
ext-user-001,用户名:test-ext-user); - 登录Keycloak控制台,通过自定义用户存储找到该用户,设置登录密码;
- 此时Keycloak会将密码哈希存储到内部
credential表; - 使用该用户名+密码登录,验证是否通过Keycloak内部凭证完成认证。
内容的提问来源于stack exchange,提问作者caihuff42
相关产品推荐
相关产品推荐

