7.5. 配置技术

我们的 PropertyFileUserStorageProvider 示例是一对一的。它被硬编码为嵌入到提供程序 jar 中的属性文件,此文件并并不有用。我们希望使此文件在提供商的实例可配置位置。换句话说,我们可能希望在多个不同域中多次重复使用此提供程序,并指向完全不同的用户属性文件。我们还要在管理控制台 UI 中执行此配置。

UserStorageProviderFactory 有额外的方法,您可以实施这些供应商配置。您描述您要为每个提供程序配置的变量,而 Admin Console 会自动呈现一个通用输入页面来收集此配置。实施时,回调方法也会在保存配置前验证配置,首次创建提供程序,以及更新时间。UserStorageProviderFactoryorg.keycloak.component.ComponentFactory 接口继承这些方法。

    List<ProviderConfigProperty> getConfigProperties();

    default
    void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel model)
            throws ComponentValidationException
    {

    }

    default
    void onCreate(KeycloakSession session, RealmModel realm, ComponentModel model) {

    }

    default
    void onUpdate(KeycloakSession session, RealmModel realm, ComponentModel model) {

    }

ComponentFactory.getConfigProperties () 方法返回 org.keycloak.provider.ProviderConfigProperty 实例列表。这些实例声明了呈现和存储提供程序配置变量所需的元数据。

7.5.1. 配置示例

让我们展开 PropertyFileUserStorageProviderFactory 示例,以便将提供商实例指向磁盘上的特定文件。

PropertyFileUserStorageProviderFactory

public class PropertyFileUserStorageProviderFactory
                  implements UserStorageProviderFactory<PropertyFileUserStorageProvider> {

    protected static final List<ProviderConfigProperty> configMetadata;

    static {
        configMetadata = ProviderConfigurationBuilder.create()
                .property().name("path")
                .type(ProviderConfigProperty.STRING_TYPE)
                .label("Path")
                .defaultValue("${jboss.server.config.dir}/example-users.properties")
                .helpText("File path to properties file")
                .add().build();
    }

    @Override
    public List<ProviderConfigProperty> getConfigProperties() {
        return configMetadata;
    }

ProviderConfigurationBuilder 类是一个很好的帮助程序类,用于创建配置属性列表。这里我们指定一个名为 path 的变量,它是 String 类型。在此提供程序的 Admin Console 配置页面上,此配置变量被标记为 Path,默认值为 ${jboss.server.config.dir}/example-users.properties。当您将鼠标指针悬停在这个配置选项提示中时,它会显示帮助文本、属性文件 的文件路径

下一个要做的事情是验证该文件是否在磁盘上。我们不想在 realm 中启用此提供程序的实例,除非它指向有效的用户属性文件。为此,我们实施 validateConfiguration () 方法。

    @Override
    public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config)
                   throws ComponentValidationException {
        String fp = config.getConfig().getFirst("path");
        if (fp == null) throw new ComponentValidationException("user property file does not exist");
        fp = EnvUtil.replace(fp);
        File file = new File(fp);
        if (!file.exists()) {
            throw new ComponentValidationException("user property file does not exist");
        }
    }

validateConfiguration () 方法中,我们从 ComponentModel 获取配置变量,并检查是否磁盘上是否存在该文件。请注意,我们使用 org.keycloak.common.util.EnvUtil.replace () 方法。使用此方法,任何具有 ${} 的字符串都将替换为一个系统属性值。${jboss.server.config.dir} 字符串对应于 服务器的配置/ 目录,在本例中非常有用。

接下来,我们要做的是删除旧的 init () 方法。我们这样做,因为用户属性文件将根据提供商实例唯一。我们将此逻辑移到 create () 方法。

    @Override
    public PropertyFileUserStorageProvider create(KeycloakSession session, ComponentModel model) {
        String path = model.getConfig().getFirst("path");

        Properties props = new Properties();
        try {
            InputStream is = new FileInputStream(path);
            props.load(is);
            is.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return new PropertyFileUserStorageProvider(session, model, props);
    }

当然,这个逻辑是效率,因为每个事务都从磁盘中读取整个用户属性文件,但希望以简单的方式表明这一点,如何在配置变量中使用 hook。

7.5.2. 在 Admin 控制台中配置供应商

现在,当在 Admin 控制台中配置供应商时,可以设置 路径 变量。