You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Keycloak User Storage SPI/Quarkus中配置动态Schema名称

实现多Schema的Keycloak JPA用户存储提供程序

要实现基于不同PostgreSQL Schema的多个用户存储实例,核心是让每个实例动态绑定指定的Schema,而非硬编码配置。以下是具体实现步骤:

1. 扩展用户存储配置项

首先在用户存储工厂类中添加Schema名称的配置项,这样在Keycloak控制台创建实例时可以手动指定Schema:

public class CustomJpaUserStorageProviderFactory implements UserStorageProviderFactory<CustomJpaUserStorageProvider> {
    // 缓存不同Schema对应的EntityManagerFactory,避免重复创建
    private final Map<String, EntityManagerFactory> emfCache = new ConcurrentHashMap<>();
    // 基础JPA配置(驱动、URL、账号密码等,可从Keycloak全局配置读取)
    private final Properties baseJpaProps = new Properties();

    @Override
    public void init(Config.Scope config) {
        // 初始化基础数据库连接配置
        baseJpaProps.put("javax.persistence.jdbc.driver", "org.postgresql.Driver");
        baseJpaProps.put("javax.persistence.jdbc.url", config.get("jdbcUrl"));
        baseJpaProps.put("javax.persistence.jdbc.user", config.get("dbUser"));
        baseJpaProps.put("javax.persistence.jdbc.password", config.get("dbPassword"));
        baseJpaProps.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
    }

    @Override
    public List<ProviderConfigProperty> getConfigProperties() {
        List<ProviderConfigProperty> props = new ArrayList<>();
        // 添加Schema名称配置项
        props.add(new ProviderConfigProperty(
            "schemaName",
            "PostgreSQL Schema名称",
            "当前用户存储实例对应的PostgreSQL Schema",
            ProviderConfigProperty.STRING_TYPE,
            null
        ));
        // 可添加其他必要配置(如JDBC地址、账号等)
        return props;
    }

    // 其他必要方法(如getId())省略
}

2. 动态创建Schema专属的EntityManagerFactory

每个用户存储实例需要独立的EntityManagerFactory,绑定指定的Schema:

@Override
public CustomJpaUserStorageProvider create(KeycloakSession session, ComponentModel model) {
    String targetSchema = model.getConfig().getFirst("schemaName");
    // 缓存中不存在则创建新的EntityManagerFactory
    EntityManagerFactory emf = emfCache.computeIfAbsent(targetSchema, schema -> {
        Properties schemaProps = new Properties(baseJpaProps);
        // 设置Hibernate默认Schema
        schemaProps.put("hibernate.default_schema", schema);
        return Persistence.createEntityManagerFactory("custom-jpa-user-storage", schemaProps);
    });
    // 创建Provider实例并传入专属EntityManager
    return new CustomJpaUserStorageProvider(session, model, emf.createEntityManager());
}

@Override
public void close() {
    // 关闭所有缓存的EntityManagerFactory
    emfCache.values().forEach(EntityManagerFactory::close);
}

3. 调整实体类映射

移除实体类中硬编码的Schema配置,让Hibernate使用EntityManagerFactory指定的默认Schema:

@Entity
@Table(name = "users") // 不指定schema,由EntityManagerFactory的default_schema控制
public class UserEntity {
    @Id
    @Column(name = "id")
    private String id;

    @Column(name = "username")
    private String username;

    // 其他字段、Getter/Setter省略
}

4. 在Provider中使用专属EntityManager

在用户存储实现类中,使用绑定了指定Schema的EntityManager进行数据库操作:

public class CustomJpaUserStorageProvider implements UserStorageProvider, UserLookupProvider {
    private final EntityManager em;
    private final KeycloakSession session;
    private final ComponentModel model;

    public CustomJpaUserStorageProvider(KeycloakSession session, ComponentModel model, EntityManager em) {
        this.session = session;
        this.model = model;
        this.em = em;
    }

    @Override
    public UserModel getUserByUsername(String username, RealmModel realm) {
        UserEntity user = em.createQuery(
                "SELECT u FROM UserEntity u WHERE u.username = :username", UserEntity.class)
            .setParameter("username", username)
            .getSingleResultOrNull();
        // 转换为Keycloak UserModel的逻辑(参考官方示例)
        return user != null ? mapToUserModel(user, realm) : null;
    }

    @Override
    public void close() {
        if (em.isOpen()) {
            em.close();
        }
    }

    // 其他必要方法(如getUserById)省略
}

最终效果

在Keycloak控制台创建用户存储实例时,分别输入不同的Schema名称,即可生成两个独立的用户存储实例,各自对应PostgreSQL中的指定Schema进行数据查询。

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 07:58:14