7.9. 导入实施策略


在实施用户存储供应商时,您可以采用另一个策略。除了使用用户联邦存储外,您可以在红帽构建的 Keycloak 内置用户数据库中在本地创建用户,并将外部存储的属性复制到这个本地副本。这种方法有很多优点。

  • 红帽构建的 Keycloak 基本上成为外部存储的持久性用户缓存。用户导入后,您将不再按外部存储,从而关闭它。
  • 如果您要以您的官方用户存储的形式迁移到红帽 Keycloak,并弃用旧的外部存储,您可以缓慢迁移应用程序以使用红帽构建的 Keycloak。迁移所有应用程序时,取消链接导入的用户,并停用旧的外部存储。

使用导入策略有一些明显的缺点:

  • 第一次查找用户将需要对红帽构建的 Keycloak 数据库进行多次更新。这可能会因为负载造成大量性能损失,并在红帽构建的 Keycloak 数据库上造成大量压力。用户联邦存储方法将仅根据需要存储额外的数据,且可能不得根据外部存储的功能使用。
  • 通过导入方法,您必须保持本地红帽构建的 Keycloak 存储和外部存储同步。用户存储 SPI 具有可用于支持同步的功能接口,但这可能会快速实现。

要实施导入策略,只需检查以首先查看用户是否在本地导入。如果是这样,如果没有在本地创建用户并从外部存储导入数据,则返回本地用户。您还可以代理本地用户,以便大多数更改会自动同步。

这将是一个位约束,但我们可以扩展我们的 PropertyFileUserStorageProvider 来实现这种方法。首先,我们首先修改 createAdapter () 方法。

PropertyFileUserStorageProvider

    protected UserModel createAdapter(RealmModel realm, String username) {
        UserModel local = UserStoragePrivateUtil.userLocalStorage(session).getUserByUsername(realm, username);
        if (local == null) {
            local = UserStoragePrivateUtil.userLocalStorage(session).addUser(realm, username);
            local.setFederationLink(model.getId());
        }
        return new UserModelDelegate(local) {
            @Override
            public void setUsername(String username) {
                String pw = (String)properties.remove(username);
                if (pw != null) {
                    properties.put(username, pw);
                    save();
                }
                super.setUsername(username);
            }
        };
    }
Copy to Clipboard Toggle word wrap

在这个方法中,我们调用 UserStoragePrivateUtil.userLocalStorage (session) 方法来获取对本地红帽构建的 Keycloak 用户存储的引用。如果没有,我们会看到用户是否存储在本地。我们会在本地添加它。不要设置本地用户的 id。让红帽构建的 Keycloak 会自动生成 id。另请注意,我们调用 UserModel.setFederationLink (),并传递我们供应商的 ComponentModel 的 ID。这会在供应商和导入的用户之间建立链接。

注意

删除用户存储提供程序时,也会删除由它导入的任何用户。这是调用 UserModel.setFederationLink () 的目的之一。

需要注意的是,如果链接了本地用户,您的存储供应商仍会委托给它从 CredentialInputValidatorCredentialInputUpdater 接口实现的方法。从验证或更新中返回 false 会导致红帽构建的 Keycloak 查看是否使用本地存储验证或更新。

另请注意,我们使用 org.keycloak.models.utils.UserModelDelegate 类代理本地用户。此类是 UserModel 的实现。每个方法都只委派给它实例化的 UserModel。我们覆盖此委派类的 setUsername () 方法,以自动与属性文件同步。对于供应商,您可以使用此选项 截获 本地 UserModel 上的其他方法,以从外部存储执行同步。例如,get 方法可以确保本地存储同步。设置方法使外部存储与本地存储保持同步。需要注意的是 getId () 方法应始终返回在本地创建用户时自动生成的 id。您不应该返回联邦 ID,如其他非导入示例所示。

注意

如果您的供应商正在实施 UserRegistrationProvider 接口,则您的 removeUser () 方法不需要从本地存储中删除该用户。运行时将自动执行此操作。另请注意,在从本地存储中删除之前,将调用 removeUser ()

7.9.1. ImportedUserValidation 接口

如果您之前在本章前面提到,我们将讨论如何查询用户工作。首先会查询本地存储(如果用户在此处找到),则查询将结束。对于上述实现,这是一个问题,因为我们希望代理本地 UserModel,以便我们可以同步用户名。用户存储 SPI 具有回调,每当链接的本地用户从本地数据库加载时。

package org.keycloak.storage.user;
public interface ImportedUserValidation {
    /**
     * If this method returns null, then the user in local storage will be removed
     *
     * @param realm
     * @param user
     * @return null if user no longer valid
     */
    UserModel validate(RealmModel realm, UserModel user);
}
Copy to Clipboard Toggle word wrap

每当加载链接的本地用户时,如果用户存储供应商类实施此接口,则调用 validate () 方法。您可以在这里代理作为参数传递的本地用户并返回它。将使用该新 UserModel。您还可以选择性地进行检查来查看用户是否仍然存在于外部存储中。如果 validate () 返回 null,则本地用户将从数据库中删除。

7.9.2. ImportSynchronization 接口

使用 import 策略,您可以看到本地用户副本可以与外部存储不同步。例如,用户可能已经从外部存储中删除。用户存储 SPI 有一个额外的接口,您可以实现来处理此接口 org.keycloak.storage.user.ImportSynchronization

package org.keycloak.storage.user;

public interface ImportSynchronization {
    SynchronizationResult sync(KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model);
    SynchronizationResult syncSince(Date lastSync, KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model);
}
Copy to Clipboard Toggle word wrap

此接口由提供商工厂实现。当此界面由提供商工厂实施后,供应商的管理控制台管理页面会显示其他选项。您可以通过单击按钮来手动强制同步。这会调用 ImportSynchronization.sync () 方法。另外,还会显示额外的配置选项,供您自动调度同步。自动同步调用 syncSince () 方法。

Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2026 Red Hat
返回顶部