第 7 章 用户存储 SPI
您可以使用用户存储 SPI 为红帽构建的 Keycloak 编写扩展,以连接到外部用户数据库和凭证存储。内置的 LDAP 和 ActiveDirectory 支持是此 SPI 在操作中实现的。开箱即用,红帽构建的 Keycloak 使用其本地数据库来创建、更新和查找用户并验证凭证。通常,机构已有现有的外部专有用户数据库,它们无法迁移到红帽构建的 Keycloak 的数据模型。对于这样的情况,应用程序开发人员可以编写用户存储 SPI 的实现来桥接外部用户存储,以及红帽构建的 Keycloak 用来登录和管理它们的内部用户对象模型。
当红帽构建的 Keycloak 运行时需要查找用户时,比如当用户登录时,它会执行多个步骤来定位用户。首先查看用户是否在用户缓存中;如果用户找到了,则使用该内存中表示。然后,它会在红帽构建的 Keycloak 本地数据库中查找用户。如果没有找到用户,则会循环通过 User Storage SPI 供应商实施来执行用户查询,直到其中一个用户返回运行时查找的用户。供应商查询外部用户存储的用户,并将用户的外部数据表示映射到红帽构建的 Keycloak 用户 metamodel。
用户存储 SPI 供应商实现也可以执行复杂的条件查询,为用户执行 CRUD 操作,验证和管理凭证,或者一次性执行许多用户的批量更新。它取决于外部存储的功能。
用户存储 SPI 提供程序实施的打包并部署与 Jakarta EE 组件类似。默认情况下,它们不会被启用,但必须在管理控制台的 User Federation
选项卡中为每个域启用和配置。
如果您的用户提供程序实施使用一些用户属性作为链接/建立用户身份的元数据属性,请确保用户无法编辑属性,并且相应的属性是只读。示例是 LDAP_ID
属性,它内置的红帽 Keycloak LDAP 供应商构建用于将用户 ID 存储在 LDAP 服务器端。请参阅 Threat 模型缓解章节中 的详细信息。
红帽构建的 Keycloak Quickstarts Repository 中有两个示例项目。每个快速入门都有一个 README
文件,其中包含如何构建、部署和测试示例项目的说明。下表提供了可用用户存储 SPI 快速入门的简单描述:
Name | 描述 |
---|---|
演示使用 JPA 实施用户存储提供程序。 | |
演示使用包含用户名/密码密钥对的简单属性文件实施用户存储提供程序。 |
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 ()
方法,然后收集实例。实例由供应商工厂创建。Provider factories 实施 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 供应商类指定为 template 参数。这必须作为运行时内省此类,以扫描其功能(它所实施的其他接口)。例如,如果您的供应商类命名为 FileProvider
,则 factory 类应类似如下:
public class FileProviderFactory implements UserStorageProviderFactory<FileProvider> { public String getId() { return "file-provider"; } public FileProvider create(KeycloakSession session, ComponentModel model) { ... }
getId ()
方法返回 User Storage 提供程序的名称。当您要为特定域启用供应商时,管理控制台的 User Federation 页面中会显示此 id。
create ()
方法负责分配提供程序类的实例。它采用 org.keycloak.models.KeycloakSession
参数。此对象可用于查找其他信息和元数据,并提供对运行时中各种其他组件的访问。ComponentModel
参数代表如何在特定域中启用和配置提供程序。它包含已启用供应商的实例 ID,以及在通过管理控制台启用时为它指定的任何配置。
UserStorageProviderFactory
还有其他功能,我们将在本章后续部分中介绍它们。