我创建了一个自定义 Keycloak 提供程序,它侦听 Kafka 主题并创建与在该主题上收到的消息相对应的组。
我已经让它大部分工作了。我仍然需要克服的唯一障碍是,在创建组后,我看不到它在管理 UI 中或在 API 调用中列出以获取领域的组列表。但我确实知道这些组被保存在数据库中,因为如果我停止并重新启动 Keycloak,那么它们就会存在。
我猜这与未更新的 Infinispan 缓存有关。我需要以某种方式告诉缓存刷新自己。有人知道怎么做这个吗?
另一件有点奇怪的事情是,我必须为此流创建自己的 KeycloakSession,并连同它一起创建一个 TransactionManager 来管理事务。这是一种相当独特的情况,因为 Keycloak 中触发的操作与用户会话无关;他们被卡夫卡消息赶走了。不确定这是否与它有关。
我的设置是这样的:
- 我创建了一个名为
GroupSyncApi. - 我定义了接口
GroupSyncProvider并分别GroupSyncProviderFactory扩展Provider和ProviderFactory - 有
GroupSyncProvider一种方法:void listen(KeycloakSessionFactory keycloakSessionFactory) - 我创建了实现
KafkaGroupSyncProvider并KafkaGroupSyncProviderFactory实现了我的自定义接口。 - 该
listen实现实例化了一个名为KafkaTopicListener. 这将启动 Kafka Consumer 和相关代码以在新线程中处理消息。该listen方法是从postInit提供者工厂的方法中调用的。这将启动线程和 Kafka 消费者。 当收到一条消息(作为 JSON)时,我将它反序列化并创建一个与之对应的 Keycloak 组。我这样做如下(这是在我的
KafkaTopicListener课上:public void listen(KeycloakSessionFactory keycloakSessionFactory) { while (true) { final ConsumerRecords<String, EntityEvent> records = consumer.poll(Duration.of(5, ChronoUnit.SECONDS)); if (!records.isEmpty()) { KeycloakSession keycloakSession = keycloakSessionFactory.create(); keycloakSession.getTransactionManager().begin(); GroupModel entitiesParent = keycloakSession.realms().getTopLevelGroups(realm).stream().filter(groupModel -> "entities".equals(groupModel.getName())).findFirst().get(); records.forEach(record -> { logger.info("Received event on Kafka '" + record.topic() + "' topic. " + record.value().getType() + " corresponding entity group with id: " + record.value().getEntity().getId() + "; name: " + record.value().getEntity().getName()); switch (record.value().getType()) { case CREATE: doCreate(keycloakSession, realm, record.value(), parent); break; } } keycloakSession.getTransactionManager().commit(); consumer.commitAsync(); } } } private void doCreate(KeycloakSession keycloakSession, RealmModel realm, EntityEvent event, GroupModel entitiesParent) { GroupModel group = keycloakSession.realms().createGroup(realm, event.getEntity().getName()); group.setAttribute("type", singleValue("entity")); group.setParent(entitiesParent); }
我不清楚的部分是:
- 我是否正确创建了一个组?
- 我的 KeycloakSession 设置是否正确?我必须手动创建它,因为此代码流不是 HTTP 请求的一部分。
- 我的事务管理器设置正确吗?