简体   繁体   English

带有 KeyCloak 的多租户 Quarkus?

[英]Multi-tenant Quarkus with KeyCloak?

I am writing a suite of services using the Quarkus framework.我正在使用Quarkus框架编写一套服务。 The services are designed to be multitenant, and are supposed to be protected using KeyCloak.这些服务被设计为多租户的,并且应该使用 KeyCloak 进行保护。 Each tenant will have a separate KeyCloak security realm, with its own set of users, groups, roles, etc.每个租户都有一个单独的 KeyCloak 安全领域,有自己的一组用户、组、角色等。

I've found the Quarkus guide to KeyCloak protection , explaining how to configure JAX-RS for authorization using KeyCloak.我找到了Quarkus 指南 KeyCloak protection ,解释了如何配置 JAX-RS 以使用 KeyCloak 进行授权。 However, this guide assumes only 1 KeyCloak realm.但是,本指南仅假设 1 个 KeyCloak 领域。 I also found this example showing how to deploy a WAR file to Wildfly that loads one of multiple KeyCloak realm configuration files depending on the specified realm.我还发现这个示例展示了如何将 WAR 文件部署到 Wildfly,该文件根据指定的领域加载多个 KeyCloak 领域配置文件之一。

However, it's not clear if this code can translate over to Quarkus.但是,尚不清楚此代码是否可以转换为 Quarkus。
Is it possible to dynamically load the KeyCloak configuration in Quarkus this way?是否可以通过这种方式在 Quarkus 中动态加载 KeyCloak 配置? Is there a better way to implement multi-tenant security for these Quarkus services?有没有更好的方法来为这些 Quarkus 服务实现多租户安全?

UPDATE: Based on Pedro and Shadov's suggestions below, I added a really simple KeycloakConfigResolver implementation and marked it as @ApplicationScoped .更新:根据下面 Pedro 和 Shadov 的建议,我添加了一个非常简单的KeycloakConfigResolver实现并将其标记为@ApplicationScoped However, when I attempted to launch Quarkus, I get the following exception and never see my custom KeycloakConfigResolver being called:但是,当我尝试启动 Quarkus 时,出现以下异常并且从未看到我的自定义KeycloakConfigResolver被调用:

17:53:55,340 INFO  [io.qua.dep.QuarkusAugmentor] Beginning quarkus augmentation
17:53:55,758 INFO  [org.jbo.threads] JBoss Threads version 3.0.0.Beta4
17:53:56,888 INFO  [org.hib.Version] HHH000412: Hibernate Core {5.4.3.Final}
17:53:57,812 INFO  [io.qua.dep.QuarkusAugmentor] Quarkus augmentation completed in 2472ms
17:53:57,967 ERROR [io.qua.dev.DevModeMain] Failed to start quarkus: java.lang.ExceptionInInitializerError
    at java.base/java.lang.J9VMInternals.ensureError(J9VMInternals.java:193)
    at java.base/java.lang.J9VMInternals.recordInitializationFailure(J9VMInternals.java:182)
    at java.base/java.lang.J9VMInternals.newInstanceImpl(Native Method)
    at java.base/java.lang.Class.newInstance(Class.java:2082)
    at io.quarkus.runner.RuntimeRunner.run(RuntimeRunner.java:117)
    at io.quarkus.dev.DevModeMain.doStart(DevModeMain.java:166)
    at io.quarkus.dev.DevModeMain.main(DevModeMain.java:88)
Caused by: java.lang.RuntimeException: Failed to start quarkus
    at io.quarkus.runner.ApplicationImpl1.<clinit>(ApplicationImpl1.zig:333)
    ... 5 more
Caused by: java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: UNKNOWN; line: 1, column: 0]
    at org.keycloak.adapters.KeycloakDeploymentBuilder.loadAdapterConfig(KeycloakDeploymentBuilder.java:198)
    at org.keycloak.adapters.KeycloakDeploymentBuilder.build(KeycloakDeploymentBuilder.java:187)
    at io.quarkus.keycloak.KeycloakTemplate.createKeycloakDeploymentContext(KeycloakTemplate.java:36)
    at io.quarkus.deployment.steps.KeycloakAdapterProcessor$configureAdapter5.deploy_0(KeycloakAdapterProcessor$configureAdapter5.zig:47)
    at io.quarkus.deployment.steps.KeycloakAdapterProcessor$configureAdapter5.deploy(KeycloakAdapterProcessor$configureAdapter5.zig:106)
    at io.quarkus.runner.ApplicationImpl1.<clinit>(ApplicationImpl1.zig:207)
    ... 5 more
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: UNKNOWN; line: 1, column: 0]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
    at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4145)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4000)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3070)
    at org.keycloak.adapters.KeycloakDeploymentBuilder.loadAdapterConfig(KeycloakDeploymentBuilder.java:196)
    ... 10 more

17:53:57,968 ERROR [io.qua.dev.DevModeMain] Failed to start Quarkus, attempting to start hot replacement endpoint to recover
17:53:58,003 INFO  [org.xnio] XNIO version 3.7.2.Final
17:53:58,017 INFO  [org.xni.nio] XNIO NIO Implementation Version 3.7.2.Final

My custom KeycloakConfigResolver is empty, save for some logging statements.我的自定义KeycloakConfigResolver是空的,除了一些日志语句。 I never see my resolve method being called or any of the logging statements.我从未看到我的resolve方法被调用或任何日志记录语句。 Here's what the implementation looks like:下面是实现的样子:

@ApplicationScoped
public class MultiTenantKeycloakConfigResolver implements KeycloakConfigResolver {

    /**
     * Logger for this class
     */
    private static final Logger logger = LoggerFactory.getLogger(MultiTenantKeycloakConfigResolver.class);

    /*
     * (non-Javadoc)
     *
     * @see
     * org.keycloak.adapters.KeycloakConfigResolver#resolve(org.keycloak.adapters.
     * spi.HttpFacade.Request)
     */
    @Override
    public KeycloakDeployment resolve(Request facade) {
        if (logger.isDebugEnabled()) {
            logger.debug("resolve(Request) - start"); //$NON-NLS-1$
        }

        if (logger.isInfoEnabled()) {
            logger.info("resolve(Request) - HERE!!!"); //$NON-NLS-1$
        }

        // TODO Implement method

        if (logger.isDebugEnabled()) {
            logger.debug("resolve(Request) - end"); //$NON-NLS-1$
        }
        return null;
    }

}

It's possible in Spring-Boot, almost the same way like in example you posted.这在 Spring-Boot 中是可能的,与您发布的示例几乎相同。 Only starting with version 4.6.0-Final tho, they added class KeycloakSpringBootConfigResolverWrapper that actually checks if there is any KeycloakConfigResolver already. KeycloakSpringBootConfigResolverWrapper 4.6.0-Final版本开始,他们添加了KeycloakSpringBootConfigResolverWrapper类,它实际上检查是否已经存在任何KeycloakConfigResolver In the previous version it was just putting it's own resolver.在以前的版本中,它只是放置了自己的解析器。 Now all you have to do is register a custom KeycloakConfigResolver bean and it works.现在你所要做的就是注册一个自定义的KeycloakConfigResolver bean,它就可以工作了。

I see there is very similiar class in Quarkus as in keycloak-spring-boot-adapters - https://github.com/quarkusio/quarkus/blob/master/extensions/keycloak/runtime/src/main/java/io/quarkus/keycloak/QuarkusKeycloakConfigResolver.java .我看到 Quarkus 中有与 keycloak-spring-boot-adapters 非常相似的类 - https://github.com/quarkusio/quarkus/blob/master/extensions/keycloak/runtime/src/main/java/io/quarkus /keycloak/QuarkusKeycloakConfigResolver.java Code is pretty obvious, no need to explain it.代码很明显,不需要解释。

Since I'm not familiar with Quarkus, I can't be 100% sure it's gonna work, but the field is annotated with Inject , so it suggests that you can just provide your own resolver, the same way as possible in Spring-Boot and in the example you posted.由于我不熟悉 Quarkus,我不能 100% 确定它会起作用,但是该字段用Inject注释,因此它建议您可以像 Spring-Boot 中一样提供自己的解析器并在您发布的示例中。

@Shadov, is right. @Shadov,是对的。 You need a KeycloakConfigResolver .你需要一个KeycloakConfigResolver

With Quarkus, you just need to create a class that implements KeycloakConfigResolver .使用 Quarkus,您只需要创建一个实现KeycloakConfigResolver的类。 Similar to this .类似。

I'll update the guide with some reference about this.我会用一些关于此的参考来更新指南。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM