第 7 章 用户存储 SPI


警告

此功能取决于 keycloak-model-legacy 和 keycloak-model-legacy -private 模块中捆绑的 API。它很快将被替换为新的映射存储 API,它提供了访问用户和其他实体的本地和外部信息的统一方法,并最终删除旧 API。

您可以使用 User Storage SPI 为红帽构建的 Keycloak 编写扩展,以连接到外部用户数据库和凭证存储。内置的 LDAP 和 sVirt 支持是此操作中此 SPI 的实现。红帽构建的 Keycloak 使用其本地数据库创建、更新和查找用户并验证凭证。虽然组织通常具有现有的外部专有用户数据库,它们无法迁移到红帽构建的 Keycloak 数据模型。对于这些情况,应用程序开发人员可编写 User Storage SPI 的实现,以桥接外部用户存储,以及红帽构建的 Keycloak 的内部用户对象模型,以管理它们。

当红帽构建的 Keycloak 运行时需要查找用户(如用户登录时),它会执行多个步骤来定位用户。首先查看用户是否在用户缓存中;如果找到了该用户,它会使用该内存表示。然后,它会在红帽构建的 Keycloak 本地数据库中查找用户。如果没有找到用户,它将通过 User Storage SPI 供应商实现循环来执行用户查询,直到其中一个用户返回运行时正在查找的用户。供应商查询外部用户存储,并将用户的外部数据表示映射到红帽构建的 Keycloak 用户 metamodel。

用户存储 SPI 提供程序实施也可以对用户执行复杂的条件查询、验证和管理凭证,或者一次性执行许多用户的批量更新。它取决于外部存储的功能。

用户存储 SPI 提供程序实施与(通常)Jakarta EE 组件类似。它们默认不启用,而是必须在管理控制台的 User Federation 选项卡下为每个域启用和配置。

警告

如果您的用户提供程序实施使用某些用户属性作为链接/建立用户身份的元数据属性,请确保用户无法编辑属性,并且对应的属性为只读。示例是 LDAP_ID 属性,内置的红帽构建的 Keycloak LDAP 供应商用于将用户的 ID 存储在 LDAP 服务器端。请参阅 Threat 模型缓解章节中 的详细信息。

红帽构建的 Keycloak Quickstarts 仓库有两个示例项目。每个快速入门都有一个 README 文件,其中包含如何构建、部署和测试示例项目的说明。下表提供了可用用户存储 SPI 快速入门的简短描述:

表 7.1. 用户存储 SPI Quickstarts
Name描述

user-storage-jpa

演示了使用 EJB 和 JPA 实施用户存储提供程序。

user-storage-simple

演示了使用包含用户名/密码密钥对的简单属性文件实施用户存储提供程序。

7.1. 供应商接口

构建用户存储 SPI 实施时,您必须定义供应商类和供应商工厂。供应商类实例由供应商工厂为每个事务创建。供应商类执行用户查找和其他用户操作的所有繁重。它们必须实施 org.keycloak.storage.UserStorageProvider 接口。

package org.keycloak.storage;

public interface UserStorageProvider extends Provider {


    /**
     * Callback when a realm is removed.  Implement this if, for example, you want to do some
     * cleanup in your user storage when a realm is removed
     *
     * @param realm
     */
    default
    void preRemove(RealmModel realm) {

    }

    /**
     * Callback when a group is removed.  Allows you to do things like remove a user
     * group mapping in your external store if appropriate
     *
     * @param realm
     * @param group
     */
    default
    void preRemove(RealmModel realm, GroupModel group) {

    }

    /**
     * Callback when a role is removed.  Allows you to do things like remove a user
     * role mapping in your external store if appropriate

     * @param realm
     * @param role
     */
    default
    void preRemove(RealmModel realm, RoleModel role) {

    }

}

您可能会认为 UserStorageProvider 接口是用户稀疏的稀疏?稍后您将在本章中看到,您的供应商类可能实施的其他混合接口来支持用户集成的机制。

UserStorageProvider 实例为每个事务创建一次。事务完成后,会调用 UserStorageProvider.close () 方法,然后实例会被垃圾回收。实例由供应商工厂创建。供应商工厂实现了 org.keycloak.storage.UserStorageProviderFactory 接口。

package org.keycloak.storage;

/**
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
 * @version $Revision: 1 $
 */
public interface UserStorageProviderFactory<T extends UserStorageProvider> extends ComponentFactory<T, UserStorageProvider> {

    /**
     * This is the name of the provider and will be shown in the admin console as an option.
     *
     * @return
     */
    @Override
    String getId();

    /**
     * called per Keycloak transaction.
     *
     * @param session
     * @param model
     * @return
     */
    T create(KeycloakSession session, ComponentModel model);
...
}

在实施 UserStorageProviderFactory 时,供应商工厂类必须将 concrete 供应商类指定为模板参数。这是一个必须,因为运行时将内省此类以扫描其功能(其实施的其他接口)。例如,如果您的供应商类命名为 FileProvider,则工厂类应类似如下:

public class FileProviderFactory implements UserStorageProviderFactory<FileProvider> {

    public String getId() { return "file-provider"; }

    public FileProvider create(KeycloakSession session, ComponentModel model) {
       ...
    }

getId () 方法返回用户存储提供程序的名称。当您想为特定域启用供应商时,控制台的 User Federation 页面中会显示此 id。

create () 方法负责分配提供程序类实例。它使用一个 org.keycloak.models.KeycloakSession 参数。此对象可用于查找其他信息和元数据,以及提供对运行时各种其他组件的访问。ComponentModel 参数代表如何在特定域中启用和配置该提供程序。它包含已启用供应商的实例 ID,以及通过管理控制台启用时可能会为其指定的任何配置。

UserStorageProviderFactory 具有其他功能,我们将在本章稍后进行。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

© 2024 Red Hat, Inc.