7.5. 简单的只读,查找示例
为了说明实施用户存储 SPI 的基础知识,让执行一个简单的示例。在本章中,您将看到一个简单的 UserStorageProvider
实施,用于在简单的属性文件中查找用户。属性文件包含用户名和密码定义,并且硬编码到 classpath 上的特定位置。提供程序将根据 ID 和用户名查找用户,并能够验证密码。源自此提供程序的用户将是只读的。
7.5.1. 供应商类 复制链接链接已复制到粘贴板!
我们首先进行的操作是 UserStorageProvider
类。
我们的供应商类 PropertyFileUserStorageProvider
实现了许多接口。它实现了 UserStorageProvider
,因为它是 SPI 的基本要求。它实现了 UserLookupProvider
接口,因为我们需要使用此提供程序存储的用户登录。它实现了 CredentialInputValidator
接口,因为我们希望使用登录屏幕验证输入的密码。我们的属性文件是只读的。我们实现了 CredentialInputUpdater
,因为当用户尝试更新其密码时,我们希望发布错误条件。
此提供程序类的结构将存储对 KeycloakSession
、componentModel
和属性文件的引用。我们稍后将使用所有这些内容。另请注意,已加载的用户映射。每当我们发现用户在此映射中时,我们都会避免在相同的事务中再次重新创建它。这是遵循许多供应商需要执行此操作(即,与 JPA 集成的任何供应商)的好做法。请记住,每个事务都会创建供应商类实例,并在事务完成后关闭。
7.5.1.1. UserLookupProvider 实现 复制链接链接已复制到粘贴板!
当用户登录时,Red Hat build of Keycloak 登录页会调用 getUserByUsername ()
方法。在我们的实施中,我们首先检查 loadedUsers
映射,以查看该用户是否已加载到此事务中。如果还没有加载,我们查看用户的属性文件。如果存在,我们创建一个 UserModel
的实现,将其存储在 加载的Users
中,以备将来参考,并返回此实例。
createAdapter ()
方法使用帮助程序类 org.keycloak.storage.adapter.AbstractUserAdapter
。这为 UserModel
提供基本实施。它使用用户的用户名作为外部 id,它根据所需的存储 id 格式自动生成用户 ID。
"f:" + component id + ":" + username
"f:" + component id + ":" + username
AbstractUserAdapter
的每个 get 方法返回 null 或空集合。但是,返回角色和组映射的方法将返回为每个用户配置的域的默认角色和组。AbstractUserAdapter
的每个集合都会抛出 org.keycloak.storage.ReadOnlyException
。因此,如果您试图修改管理控制台中的用户,则会出现错误。
getUserById ()
方法使用 org.keycloak.storage.StorageId
helper 类解析 id
参数。调用 StorageId.getExternalId ()
方法,以获取嵌入在 id
参数中的用户名。然后,该方法将委派给 getUserByUsername ()
。
电子邮件不存储,因此 getUserByEmail ()
方法返回 null。
7.5.1.2. CredentialInputValidator 实现 复制链接链接已复制到粘贴板!
接下来,查看 CredentialInputValidator
的方法实现。
运行时调用 isConfiguredFor ()
方法,以确定是否为用户配置了特定凭证类型。此方法检查是否为用户设置密码。
supportsCredentialType ()
方法返回是否针对特定凭证类型支持验证。我们检查凭据类型是 密码
。
isValid ()
方法负责验证密码。CredentialInput
参数实际上只是适用于所有凭证类型的抽象接口。我们确保支持凭证类型,也是 UserCredentialModel
实例。当用户通过登录页面登录时,密码输入的纯文本将放入 UserCredentialModel
实例中。isValid ()
方法根据存储在属性文件中的纯文本密码检查此值。返回值为 true
表示密码有效。
7.5.1.3. CredentialInputUpdater 实现 复制链接链接已复制到粘贴板!
如前所述,我们实现这个示例中的 CredentialInputUpdater
接口的唯一原因是禁止修改用户密码。我们必须这样做的原因是,否则运行时允许在红帽构建的 Keycloak 本地存储中覆盖密码。本章稍后将讨论更多相关信息。
updateCredential ()
方法只检查凭证类型是否为 password。如果是,则会抛出 ReadOnlyException
。
7.5.2. 供应商工厂实施 复制链接链接已复制到粘贴板!
现在,供应商类已完成,我们现在将注意到供应商工厂类。
首先要注意的是,在实施 UserStorageProviderFactory
类时,您必须传递 concrete 供应商类实施作为模板参数。在这里,我们指定之前定义的供应商类: PropertyFileUserStorageProvider
。
如果没有指定 template 参数,您的供应商将无法正常工作。运行时执行类内省来确定提供程序实施 的功能接口。
getId ()
方法标识运行时中的工厂,当您要为域启用用户存储供应商时,也将是管理控制台中显示的字符串。
7.5.2.1. 初始化 复制链接链接已复制到粘贴板!
UserStorageProviderFactory
接口有一个可选的 init ()
方法,您可以实现。当红帽构建的 Keycloak 引导时,只会为每个供应商工厂创建一个实例。在引导时,每个工厂实例都会调用 init ()
方法。还有一个 postInit ()
方法,也可以实现。调用每个工厂的 init ()
方法后,会调用其 postInit ()
方法。
在 init ()
方法实施中,我们从 classpath 找到包含用户声明的属性文件。然后,我们使用存储在其中的用户名和密码的组合来加载 properties
字段。
Config.Scope
参数是通过服务器配置配置的工厂配置。
例如,使用以下参数运行服务器:
kc.[sh|bat] start --spi-storage-readonly-property-file-path=/other-users.properties
kc.[sh|bat] start --spi-storage-readonly-property-file-path=/other-users.properties
我们可以指定用户属性文件的类路径,而不是硬编码它。然后您可以在 PropertyFileUserStorageProviderFactory.init ()
中检索配置:
7.5.2.2. 创建方法 复制链接链接已复制到粘贴板!
创建提供程序工厂的最后一步是 create ()
方法。
@Override public PropertyFileUserStorageProvider create(KeycloakSession session, ComponentModel model) { return new PropertyFileUserStorageProvider(session, model, properties); }
@Override
public PropertyFileUserStorageProvider create(KeycloakSession session, ComponentModel model) {
return new PropertyFileUserStorageProvider(session, model, properties);
}
我们只是分配 PropertyFileUserStorageProvider
类。这个创建方法将为每个事务调用一次。
7.5.3. 打包和部署 复制链接链接已复制到粘贴板!
我们提供程序实施的类文件应放在 jar 中。您还必须在 META-INF/services/org.keycloak.storage.UserStorageProviderFactory
文件中声明供应商工厂类。
org.keycloak.examples.federation.properties.FilePropertiesStorageFactory
org.keycloak.examples.federation.properties.FilePropertiesStorageFactory
要部署此 jar,将其复制到 provider/
目录中,然后运行 bin/kc.[sh|bat] build
。
7.5.4. 在管理门户中启用供应商 复制链接链接已复制到粘贴板!
您可以在管理控制台的 User Federation 页面中启用每个域的用户存储供应商。
用户联邦
流程
从列表中选择我们刚才创建的提供程序:
readonly-property-file
。此时会显示我们的提供程序的配置页面。
点 Save,因为没有配置。
配置的供应商
返回到主 User Federation 页面
现在,您会看到列出了您的供应商。
用户联邦
现在,您将能够使用 users.properties
文件中声明的用户登录。此用户只能在登录后查看帐户页面。