编辑此页面

使用 OpenID Connect (OIDC) 和 Keycloak 集中授权

了解如何通过使用 Keycloak 授权服务来保护对受保护资源的访问,从而在您的 Quarkus 应用程序中启用持有者令牌授权。

概述

Keycloak 授权扩展,quarkus-keycloak-authorization,扩展了 OpenID Connect 扩展,quarkus-oidc,以提供高级授权功能。它具有一个策略执行器,可以动态地管理对安全资源的访问。访问受 Keycloak 中定义的权限控制,支持灵活和动态的基于资源的访问控制 (RBAC)。

仅当您使用 Keycloak 并且您的环境中启用了 Keycloak 授权服务功能来处理授权决策时,才使用 quarkus-keycloak-authorization 扩展。

如果您不使用 Keycloak,或者 Keycloak 配置为未启用 Keycloak 授权服务功能,请改用 quarkus-oidc 扩展。

工作原理

quarkus-keycloak-authorization 扩展将授权责任集中在 Keycloak 中,从而增强了安全性并简化了应用程序维护。

  • 它使用 quarkus-oidc 扩展来验证持有者令牌。

  • 它将验证后的令牌发送到 Keycloak 授权服务。

  • 它允许 Keycloak 通过使用资源名称、标识符或 URI 等属性动态评估基于资源的权限。

通过外部化授权决策,您可以

  • 实施不同的访问控制策略,而无需修改应用程序代码。

  • 随着安全需求的演变,减少重新部署的需求。

兼容性

此扩展仅与 Quarkus OIDC 服务应用程序兼容。它通过动态授权策略补充了显式机制,例如基于角色的访问控制。

主要功能
  • 集中式管理:将授权决策委托给 Keycloak,以便在应用程序中实现一致的安全策略。

  • 动态权限:通过使用资源属性动态定义访问控制。

  • 简化维护:当访问策略发生更改时,减少更新和重新部署应用程序的需要。

设置

在使用此扩展之前,请确保以下事项

  1. Keycloak 实例中已启用 Keycloak 授权服务功能。

  2. 您的 Quarkus 应用程序包含 quarkus-keycloak-authorization 扩展。

有关详细步骤,请参阅 OIDC 持有者令牌身份验证指南。

其他资源

要了解有关 Keycloak 授权服务和策略执行器的更多信息,请访问官方文档:Keycloak 授权服务文档

先决条件

要完成本指南,您需要

  • 大约 15 分钟

  • 一个 IDE

  • 已安装 JDK 17+ 并正确配置了 JAVA_HOME

  • Apache Maven 3.9.9

  • 一个正常工作的容器运行时(Docker 或 Podman

  • 如果您想使用它,可以选择 Quarkus CLI

  • 如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置

  • jq 工具

  • Keycloak

架构

此示例演示了一个简单的微服务设置,其中包含两个受保护的端点

  • /api/users/me

  • /api/admin

基于令牌的访问控制

对这些端点的访问通过使用持有者令牌来控制。要获得访问权限,必须满足以下条件

  • 有效令牌:令牌必须具有正确的签名、有效的到期日期和适当的受众。

  • 信任:微服务必须信任颁发 Keycloak 服务器。

Keycloak 服务器颁发的持有者令牌用作

  • 用户标识符:指示为其颁发令牌的主题(用户)。

  • 客户端引用:根据 OAuth 2.0 授权服务器标准,识别代表用户执行操作的客户端应用程序。

端点和访问策略

对于 /api/users/me

  • 访问策略:对具有有效持有者令牌和 user 角色的用户开放。

  • 响应:以从令牌派生的 JSON 对象形式返回用户详细信息。

    示例响应
    {
      "user": {
        "id": "1234",
        "username": "johndoe",
        "email": "johndoe@example.com"
      }
    }

对于 /api/admin

  • 访问策略:限制为具有有效持有者令牌和 admin 角色的用户。

解耦授权

此示例重点介绍了使用基于角色的访问控制 (RBAC) 策略来保护资源。关键点包括

  • 策略灵活性:Keycloak 支持各种策略类型,例如基于属性的策略和自定义策略,从而实现精细控制。

  • 解耦的应用程序逻辑:授权策略完全由 Keycloak 管理,从而使您的应用程序可以专注于其核心功能。

解决方案

我们建议您按照以下章节中的说明,逐步创建应用程序。但是,您可以直接转到完整的示例。

克隆 Git 存储库:git clone https://github.com/quarkusio/quarkus-quickstarts.git,或下载 存档

解决方案位于 security-keycloak-authorization-quickstart 目录中。

创建项目

要开始使用,请使用以下命令创建一个新项目

CLI
quarkus create app org.acme:security-keycloak-authorization-quickstart \
    --extension='oidc,keycloak-authorization,rest-jackson' \
    --no-code
cd security-keycloak-authorization-quickstart

要创建 Gradle 项目,请添加 --gradle--gradle-kotlin-dsl 选项。

有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.24.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=security-keycloak-authorization-quickstart \
    -Dextensions='oidc,keycloak-authorization,rest-jackson' \
    -DnoCode
cd security-keycloak-authorization-quickstart

要创建 Gradle 项目,请添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

对于 Windows 用户

  • 如果使用 cmd,(不要使用反斜杠 \ 并将所有内容放在同一行上)

  • 如果使用 Powershell,请将 -D 参数包装在双引号中,例如 "-DprojectArtifactId=security-keycloak-authorization-quickstart"

此命令生成一个具有 keycloak-authorization 扩展的新项目。该扩展将 Keycloak 适配器集成到您的 Quarkus 应用程序中,从而提供与 Keycloak 服务器交互并执行持有者令牌授权的必要功能。

将扩展添加到现有项目

如果您已经有一个现有的 Quarkus 项目,则可以通过在项目的基本目录中运行以下命令来添加 oidckeycloak-authorization 扩展

CLI
quarkus extension add oidc,keycloak-authorization
Maven
./mvnw quarkus:add-extension -Dextensions='oidc,keycloak-authorization'
Gradle
./gradlew addExtension --extensions='oidc,keycloak-authorization'

此命令将以下依赖项添加到您的构建文件中

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-oidc</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-keycloak-authorization</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-oidc")
implementation("io.quarkus:quarkus-keycloak-authorization")
实现 /api/users/me 端点

首先实现 /api/users/me 端点。以下代码定义了一个 Jakarta REST 资源,该资源提供用户详细信息

package org.acme.security.keycloak.authorization;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.jboss.resteasy.reactive.NoCache;

import io.quarkus.security.identity.SecurityIdentity;

@Path("/api/users")
public class UsersResource {

    @Inject
    SecurityIdentity identity;

    @GET
    @Path("/me")
    @NoCache
    public User me() {
        return new User(identity);
    }

    public static class User {

        private final String userName;

        User(SecurityIdentity identity) {
            this.userName = identity.getPrincipal().getName();
        }

        public String getUserName() {
            return userName;
        }
    }
}
实现 /api/admin 端点

接下来,定义 /api/admin 端点。以下代码表示一个简单的受身份验证保护的 Jakarta REST 资源

package org.acme.security.keycloak.authorization;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import io.quarkus.security.Authenticated;

@Path("/api/admin")
@Authenticated
public class AdminResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String admin() {
        return "granted";
    }
}
使用 Keycloak 进行基于角色的访问控制

请注意,未定义显式注释(例如 @RolesAllowed)来强制执行对资源的访问控制。相反,keycloak-authorization 扩展会动态映射 Keycloak 中受保护资源的 URI。

访问控制管理如下

  • Keycloak 根据其配置的策略评估每个请求的权限。

  • 该扩展强制执行这些权限,根据 Keycloak 中定义的角色或策略授予或拒绝访问权限。

这会将访问控制逻辑与应用程序代码分离,从而更易于直接在 Keycloak 中管理和更新访问策略。

配置应用程序

您可以使用 OpenID Connect 扩展通过 application.properties 文件(通常位于 src/main/resources 目录中)来配置适配器设置。例如

# OIDC Configuration
%prod.quarkus.oidc.auth-server-url=https://:8543/realms/quarkus (1)
quarkus.oidc.client-id=backend-service (2)
quarkus.oidc.credentials.secret=secret (3)
quarkus.oidc.tls.verification=none (4)

# Enable Policy Enforcement
quarkus.keycloak.policy-enforcer.enable=true (5)

# Import the realm file with Dev Services for Keycloak
# Note: This property is effective only in dev mode, not in JVM or native modes
quarkus.keycloak.devservices.realm-path=quarkus-realm.json (6)
1 指定 Keycloak 服务器的 URL 以及用于身份验证的领域。
2 标识 Keycloak 领域中的客户端应用程序。
3 定义与 Keycloak 服务器进行身份验证的客户端密钥。
4 出于开发目的禁用 TLS 验证,不建议用于生产。
5 启用 Keycloak 策略执行器以根据定义的权限管理访问控制。
6 配置开发服务以导入指定的领域文件,仅在开发模式下有效,而在 JVM 或本机模式下无效。

%prod. 配置文件前缀添加到 quarkus.oidc.auth-server-url 可确保 Keycloak 的开发服务自动在开发模式下启动容器。有关更多详细信息,请参阅 在开发模式下运行应用程序部分。

默认情况下,使用 quarkus-oidc 扩展的应用程序被视为 service 类型应用程序。但是,该扩展还支持以下条件下的 web-app 类型应用程序

  • 在授权代码授予流程期间返回的访问令牌必须是角色的来源 (quarkus.oidc.roles.source=accesstoken)。

  • 注意:对于 web-app 类型应用程序,默认情况下会检查 ID 令牌角色。

启动和配置 Keycloak 服务器

在开发模式下运行应用程序时,请勿启动 Keycloak 服务器。Keycloak 的开发服务会启动一个容器。有关更多信息,请参阅 在开发模式下运行应用程序部分。

要启动 Keycloak 服务器,请使用以下 Docker 命令

docker run --name keycloak \
  -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
  -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
  -p 8543:8443 \
  -v "$(pwd)"/config/keycloak-keystore.jks:/etc/keycloak-keystore.jks \
  quay.io/keycloak/keycloak:{keycloak.version} \ (1)
  start --hostname-strict=false --https-key-store-file=/etc/keycloak-keystore.jks (2)
1 对于 keycloak.version,请确保版本为 26.2.4 或更高版本。
2 对于 Keycloak 密钥库,请使用位于 quarkus-quickstarts/security-keycloak-authorization-quickstart/configkeycloak-keystore.jks 文件。
访问 Keycloak 服务器
  1. 打开浏览器并导航到 https://:8543

  2. 使用以下凭据登录到 Keycloak 管理控制台

    • 用户名admin

    • 密码admin

导入领域配置

要创建新领域,请导入 领域配置文件。有关创建领域的详细步骤,请参阅 Keycloak 文档:创建新领域

导入领域后,转到“客户端”,选择 backend-service 客户端,然后为此客户端选择“授权”和“资源”选项卡。您现在可以查看资源权限

Keycloak Authorization Permissions
Keycloak 在资源权限中的作用

资源访问权限直接在 Keycloak 中配置,这消除了在您的应用程序代码中对 @RolesAllowed 注释的需求。这种方法将访问控制管理集中在 Keycloak 中,从而简化了应用程序维护和安全更新。

在开发模式下运行应用程序

要在开发模式下运行应用程序,请使用以下命令

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

Keycloak 的开发服务启动一个 Keycloak 容器并导入 quarkus-realm.json 配置文件。

打开 开发 UI(可在 /q/dev-ui 中访问),然后单击开发 UI 中 OpenID Connect 卡上的 Provider: Keycloak 链接。

与开发 UI 交互
  1. /q/dev-ui 中打开 开发 UI

  2. 单击开发 UI 中 OpenID Connect 卡内的 Provider: Keycloak 链接。

测试用户权限

当提示登录到 OpenID Connect Dev UI 提供的 Single Page Application 时,请执行以下操作

  1. alice(密码:alice)身份登录,她只有 User Permission 才能访问 /api/users/me 资源

    1. 访问 /api/admin,它返回 403

    2. 访问 /api/users/me,它返回 200

  2. 注销并以 admin(密码:admin)身份登录,他既具有访问 /api/admin 资源的 Admin Permission,又具有访问 /api/users/me 资源的 User Permission

    1. 访问 /api/admin,它返回 200

    2. 访问 /api/users/me,它返回 200

自定义 Keycloak 领域

如果您在没有导入领域文件(例如 quarkus-realm.json)的情况下启动了 Keycloak 的开发服务,请创建一个没有 Keycloak 授权策略的默认 quarkus 领域

  1. 从开发 UI 中的 OpenID Connect 卡中选择 Keycloak Admin 链接。

  2. 登录到 Keycloak 管理控制台。用户名和密码均为 admin

  3. 按照 Keycloak 授权服务文档中的说明在 quarkus 领域中启用授权策略。

Keycloak Admin 链接很容易在开发 UI 中找到

Dev UI OpenID Connect Card
添加自定义 JavaScript 策略

如果您的应用程序使用配置了 JavaScript 策略的 Keycloak 授权,这些策略部署在 JAR 存档中,则 Keycloak 的开发服务可以将此存档传输到 Keycloak 容器。使用 application.properties 中的以下属性来配置传输

# Alias the policies archive
quarkus.keycloak.devservices.resource-aliases.policies=/policies.jar (1)
# Map the policies archive to a specific location in the container
quarkus.keycloak.devservices.resource-mappings.policies=/opt/keycloak/providers/policies.jar (2)
1 /policies.jar 类路径资源创建 policies 别名。策略存档也可以位于文件系统上。
2 将策略存档映射到 Keycloak 容器内的 /opt/keycloak/providers/policies.jar 位置。

在 JVM 模式下运行应用程序

在开发模式下浏览应用程序后,您可以在 JVM 模式下将其作为标准 Java 应用程序运行。

编译应用程序

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

运行应用程序

java -jar target/quarkus-app/quarkus-run.jar

在本机模式下运行应用程序

您可以将此演示编译为本机代码;不需要进行修改。

本机编译消除了生产环境中对 JVM 的需求,因为生成的二进制文件包含运行时并且针对最小资源使用进行了优化。

编译需要更长的时间,并且默认情况下处于禁用状态。要构建应用程序,请启用 native 配置文件。

构建本机二进制文件

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true

稍后,运行本机二进制文件

./target/security-keycloak-authorization-quickstart-1.0.0-SNAPSHOT-runner

测试应用程序

有关在开发模式下测试应用程序的说明,请参阅前面的 在开发模式下运行应用程序部分。

您可以使用 curl 测试在 JVM 或本机模式下运行的应用程序。

获取访问令牌

该应用程序使用持有者令牌授权。要访问其资源,请首先从 Keycloak 服务器获取访问令牌

export access_token=$(\
    curl --insecure -X POST https://:8543/realms/quarkus/protocol/openid-connect/token \
    --user backend-service:secret \
    -H 'content-type: application/x-www-form-urlencoded' \
    -d 'username=alice&password=alice&grant_type=password' | jq --raw-output '.access_token' \
 )

如果 quarkus.oidc.authentication.user-info-required 属性设置为 true,则应用程序需要使用访问令牌来请求 UserInfo。在这种情况下,您必须将 scope=openid 查询参数添加到令牌授予请求中;例如

export access_token=$(\
    curl --insecure -X POST https://:8180/realms/quarkus/protocol/openid-connect/token \
    --user backend-service:secret \
    -H 'content-type: application/x-www-form-urlencoded' \
    -d 'username=alice&password=alice&grant_type=password&scope=openid' | jq --raw-output '.access_token' \
 )

前面的示例获取用户 alice 的访问令牌。

访问 /api/users/me 端点

任何具有有效访问令牌的用户都可以访问 https://:8080/api/users/me 端点,该端点返回包含用户详细信息的 JSON 有效负载

curl -v -X GET \
  https://:8080/api/users/me \
  -H "Authorization: Bearer "$access_token
访问 /api/admin 端点

https://:8080/api/admin 端点仅限于具有 admin 角色的用户。如果您尝试使用先前颁发的访问令牌访问此端点,则服务器将返回 403 Forbidden 响应

curl -v -X GET \
  https://:8080/api/admin \
  -H "Authorization: Bearer "$access_token
获取管理员访问令牌

要访问管理员端点,请获取用户 admin 的访问令牌

export access_token=$(\
    curl --insecure -X POST https://:8543/realms/quarkus/protocol/openid-connect/token \
    --user backend-service:secret \
    -H 'content-type: application/x-www-form-urlencoded' \
    -d 'username=admin&password=admin&grant_type=password' | jq --raw-output '.access_token' \
 )

注入授权客户端

您可以使用 Keycloak 授权客户端 Java API 来执行高级任务,例如直接从 Keycloak 管理资源和获取权限。要启用此功能,请将 AuthzClient 实例注入到您的 bean 中

public class ProtectedResource {
    @Inject
    AuthzClient authzClient;
}
如果要直接使用 AuthzClient,请设置 quarkus.keycloak.policy-enforcer.enable=true;否则,没有可用于注入的 bean。

要直接使用 AuthzClient,请设置 quarkus.keycloak.policy-enforcer.enable=true。否则,没有可用于注入的 bean。

映射受保护的资源

默认情况下,扩展程序会按需从 Keycloak 获取资源,使用其 URI 来识别和映射需要保护的应用程序资源。

要禁用按需获取并在启动时预加载资源,请配置以下属性

quarkus.keycloak.policy-enforcer.lazy-load-paths=false

从 Keycloak 预加载资源所需的时间取决于资源的数量,这可能会影响应用程序的初始加载时间。

有关配置受保护资源的更多信息

在默认配置中,Keycloak 管理角色并决定谁可以访问哪些路由。

要通过使用 @RolesAllowed 注释或 application.properties 文件来配置受保护的路由,请查看 OpenID Connect (OIDC) 持有者令牌身份验证Web 端点授权指南。有关更多详细信息,请查看 Quarkus 安全概述

访问公共资源

要允许访问公共资源而不应用 quarkus-keycloak-authorization 策略,请在 application.properties 文件中定义一个 permit HTTP 策略。有关更多信息,请参阅 Web 端点授权指南。

使用以下配置时,您无需禁用 Keycloak 授权策略的策略检查

quarkus.keycloak.policy-enforcer.paths.1.paths=/api/public
quarkus.keycloak.policy-enforcer.paths.1.enforcement-mode=DISABLED

要限制匿名用户对公共资源的访问,请定义一个强制执行的 Keycloak 授权策略

quarkus.keycloak.policy-enforcer.paths.1.paths=/api/public-enforcing
quarkus.keycloak.policy-enforcer.paths.1.enforcement-mode=ENFORCING

当需要控制对公共资源的匿名访问时,仅应用默认租户配置。

以编程方式检查权限范围

除了资源权限之外,您还可以定义方法范围。范围通常表示对资源执行的操作。您可以使用方法范围创建一个强制执行的 Keycloak 授权策略。例如

# path policy with enforced scope 'read' for method 'GET'
quarkus.keycloak.policy-enforcer.paths.1.name=Scope Permission Resource
quarkus.keycloak.policy-enforcer.paths.1.paths=/api/protected/standard-way
quarkus.keycloak.policy-enforcer.paths.1.methods.get.method=GET
quarkus.keycloak.policy-enforcer.paths.1.methods.get.scopes=read (1)

# path policies without scope
quarkus.keycloak.policy-enforcer.paths.2.name=Scope Permission Resource
quarkus.keycloak.policy-enforcer.paths.2.paths=/api/protected/programmatic-way,/api/protected/annotation-way
1 用户必须具有资源权限 Scope Permission Resource 和范围 read

Keycloak 策略执行器保护 /api/protected/standard-way 请求路径,从而无需使用诸如 @RolesAllowed 之类的注释。但是,在某些情况下,您可能需要执行编程检查。

您可以通过将 SecurityIdentity 实例注入到您的 bean 中来实现此目的,如以下示例所示。或者,您可以通过使用 @PermissionsAllowed 注释资源方法来获得相同的结果。以下示例演示了三种资源方法,每种方法都需要相同的 read 范围

import java.security.BasicPermission;
import java.util.List;

import jakarta.inject.Inject;
import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.keycloak.representations.idm.authorization.Permission;

import io.quarkus.security.PermissionsAllowed;
import io.quarkus.security.identity.SecurityIdentity;
import io.smallrye.mutiny.Uni;

@Path("/api/protected")
public class ProtectedResource {

    @Inject
    SecurityIdentity identity;

    @GET
    @Path("/standard-way")
    public Uni<List<Permission>> standardWay() { (1)
        return Uni.createFrom().item(identity.<List<Permission>> getAttribute("permissions"));
    }

    @GET
    @Path("/programmatic-way")
    public Uni<List<Permission>> programmaticWay() {
        var requiredPermission = new BasicPermission("Scope Permission Resource") {
            @Override
            public String getActions() {
                return "read";
            }
        };
        return identity.checkPermission(requiredPermission).onItem() (2)
                .transform(granted -> {
                    if (granted) {
                        return identity.getAttribute("permissions");
                    }
                    throw new ForbiddenException();
                });
    }

    @PermissionsAllowed("Scope Permission Resource:read") (3)
    @GET
    @Path("/annotation-way")
    public Uni<List<Permission>> annotationWay() {
        return Uni.createFrom().item(identity.<List<Permission>> getAttribute("permissions"));
    }
}
1 /standard-way 子路径需要基于 application.properties 文件中设置的配置的资源权限和 read 范围。
2 默认情况下,/programmatic-way 子路径仅检查 Scope Permission Resource 权限。但是,您可以通过使用 SecurityIdentity#checkPermission 来强制执行其他约束,例如范围要求。
3 /annotation-way 处的 @PermissionsAllowed 注释限制对具有 Scope Permission Resource 权限以及 read 范围的请求的访问。有关更多信息,请参阅 Web 端点授权指南的 使用注释进行授权部分。

多租户

您可以为每个租户设置策略执行器配置,类似于 OpenID Connect (OIDC) 多租户的方式。例如

quarkus.keycloak.policy-enforcer.enable=true

# Default Tenant
quarkus.oidc.auth-server-url=${keycloak.url:replaced-by-test-resource}/realms/quarkus
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.secret=secret

quarkus.keycloak.policy-enforcer.enforcement-mode=PERMISSIVE
quarkus.keycloak.policy-enforcer.paths.1.name=Permission Resource
quarkus.keycloak.policy-enforcer.paths.1.paths=/api/permission
quarkus.keycloak.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim

# Service Tenant

quarkus.oidc.service-tenant.auth-server-url=${keycloak.url:replaced-by-test-resource}/realms/quarkus
quarkus.oidc.service-tenant.client-id=quarkus-app
quarkus.oidc.service-tenant.credentials.secret=secret

quarkus.keycloak.service-tenant.policy-enforcer.enforcement-mode=PERMISSIVE
quarkus.keycloak.service-tenant.policy-enforcer.paths.1.name=Permission Resource Service
quarkus.keycloak.service-tenant.policy-enforcer.paths.1.paths=/api/permission
quarkus.keycloak.service-tenant.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim


# WebApp Tenant

quarkus.oidc.webapp-tenant.auth-server-url=${keycloak.url:replaced-by-test-resource}/realms/quarkus
quarkus.oidc.webapp-tenant.client-id=quarkus-app
quarkus.oidc.webapp-tenant.credentials.secret=secret
quarkus.oidc.webapp-tenant.application-type=web-app
quarkus.oidc.webapp-tenant.roles.source=accesstoken

quarkus.keycloak.webapp-tenant.policy-enforcer.enforcement-mode=PERMISSIVE
quarkus.keycloak.webapp-tenant.policy-enforcer.paths.1.name=Permission Resource WebApp
quarkus.keycloak.webapp-tenant.policy-enforcer.paths.1.paths=/api/permission
quarkus.keycloak.webapp-tenant.policy-enforcer.paths.1.claim-information-point.claims.static-claim=static-claim

动态租户配置解析

要为多个租户创建配置,同时避免在配置文件中出现过多的条目,您可以使用 io.quarkus.keycloak.pep.TenantPolicyConfigResolver 接口以编程方式在运行时定义它们。

package org.acme.security.keycloak.authorization;

import java.util.Map;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.keycloak.pep.TenantPolicyConfigResolver;
import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerConfig;
import io.quarkus.keycloak.pep.runtime.KeycloakPolicyEnforcerTenantConfig;
import io.quarkus.oidc.OidcRequestContext;
import io.quarkus.oidc.OidcTenantConfig;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomTenantPolicyConfigResolver implements TenantPolicyConfigResolver {

    private final KeycloakPolicyEnforcerTenantConfig enhancedTenantConfig;
    private final KeycloakPolicyEnforcerTenantConfig newTenantConfig;

    public CustomTenantPolicyConfigResolver(KeycloakPolicyEnforcerConfig enforcerConfig) {
        this.enhancedTenantConfig = KeycloakPolicyEnforcerTenantConfig.builder(enforcerConfig.defaultTenant()) (1)
            .paths("/enhanced-config")
            .permissionName("Permission Name")
            .get("read-scope")
            .build();
        this.newTenantConfig = KeycloakPolicyEnforcerTenantConfig.builder() (2)
            .paths("/new-config")
            .claimInformationPoint(Map.of("claims", Map.of("grant", "{request.parameter['grant']}")))
            .build();
    }

    @Override
    public Uni<KeycloakPolicyEnforcerTenantConfig> resolve(RoutingContext routingContext, OidcTenantConfig tenantConfig,
                                                OidcRequestContext<KeycloakPolicyEnforcerTenantConfig> requestContext) {
        String path = routingContext.normalizedPath();
        String tenantId = tenantConfig.tenantId().orElse(null);
        if ("enhanced-config-tenant".equals(tenantId) && path.equals("/enhanced-config")) {
            return Uni.createFrom().item(enhancedTenantConfig);
        } else if ("new-config-tenant".equals(tenantId) && path.equals("/new-config")) {
            return Uni.createFrom().item(newTenantConfig);
        }
        return Uni.createFrom().nullItem(); (3)
    }
}
1 在默认租户配置中定义或更新 /enhanced-config 路径。
2 /new-config 路径添加到租户配置,包括以编程方式填充的自定义声明和值。
3 回退到在 application.properties 文件或其他 SmallRye Config 源中定义的默认静态租户配置解析。

配置参考

此配置符合官方 Keycloak 策略执行器配置指南。有关各种配置选项的详细见解,请参阅以下文档

构建时固定的配置属性 - 所有其他配置属性都可以在运行时覆盖

配置属性

类型

默认

启用策略执行。

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_ENABLE

显示更多

布尔值

false

适配器将对 Keycloak 服务器进行单独的 HTTP 调用,以将访问代码转换为访问令牌。此配置选项定义应池化到 Keycloak 服务器的连接数

环境变量:QUARKUS_KEYCLOAK_CONNECTION_POOL_SIZE

显示更多

整数

20

指定如何强制执行策略。

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_ENFORCEMENT_MODE

显示更多

permissive, enforcing, disabled

enforcing

定义应保留在缓存中的条目限制

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATH_CACHE_MAX_ENTRIES

显示更多

整数

1000

定义条目应过期的毫秒数

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATH_CACHE_LIFESPAN

显示更多

long

30000

指定适配器应如何从服务器获取与应用程序中的路径关联的资源。如果为 true,则策略执行器将根据所请求的路径按需获取资源

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_LAZY_LOAD_PATHS

显示更多

布尔值

true

复杂配置。

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_CLAIM_INFORMATION_POINT__COMPLEX_CONFIG_

显示更多

Map<String,Map<String,Map<String,String>>>

简单配置。

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_CLAIM_INFORMATION_POINT__SIMPLE_CONFIG_

显示更多

Map<String,Map<String,String>>

指定应如何将范围映射到 HTTP 方法。如果设置为 true,则策略执行器将使用当前请求中的 HTTP 方法来检查是否应授予访问权限

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_HTTP_METHOD_AS_SCOPE

显示更多

布尔值

false

服务器上要与给定路径关联的资源的名称

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATHS__PATHS__NAME

显示更多

字符串

应由策略执行器保护的 HTTP 请求路径

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATHS__PATHS__PATHS

显示更多

字符串列表

HTTP 方法的名称

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATHS__PATHS__METHODS__METHODS__METHOD

显示更多

字符串

必需

与方法关联的范围的字符串数组

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATHS__PATHS__METHODS__METHODS__SCOPES

显示更多

字符串列表

必需

引用与方法关联的范围的强制执行模式的字符串

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATHS__PATHS__METHODS__METHODS__SCOPES_ENFORCEMENT_MODE

显示更多

all, any, disabled

all

指定如何强制执行策略

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATHS__PATHS__ENFORCEMENT_MODE

显示更多

permissive, enforcing, disabled

enforcing

复杂配置。

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATHS__PATHS__CLAIM_INFORMATION_POINT__COMPLEX_CONFIG_

显示更多

Map<String,Map<String,Map<String,String>>>

简单配置。

环境变量:QUARKUS_KEYCLOAK_POLICY_ENFORCER_PATHS__PATHS__CLAIM_INFORMATION_POINT__SIMPLE_CONFIG_

显示更多

Map<String,Map<String,String>>

其他命名租户

类型

默认

适配器将对 Keycloak 服务器进行单独的 HTTP 调用,以将访问代码转换为访问令牌。此配置选项定义应池化到 Keycloak 服务器的连接数

环境变量:QUARKUS_KEYCLOAK__TENANT__CONNECTION_POOL_SIZE

显示更多

整数

20

指定如何强制执行策略。

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_ENFORCEMENT_MODE

显示更多

permissive, enforcing, disabled

enforcing

服务器上要与给定路径关联的资源的名称

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__NAME

显示更多

字符串

应由策略执行器保护的 HTTP 请求路径

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__PATHS

显示更多

字符串列表

HTTP 方法的名称

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__METHODS__METHODS__METHOD

显示更多

字符串

必需

与方法关联的范围的字符串数组

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__METHODS__METHODS__SCOPES

显示更多

字符串列表

必需

引用与方法关联的范围的强制执行模式的字符串

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__METHODS__METHODS__SCOPES_ENFORCEMENT_MODE

显示更多

all, any, disabled

all

指定如何强制执行策略

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__ENFORCEMENT_MODE

显示更多

permissive, enforcing, disabled

enforcing

复杂配置。

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__CLAIM_INFORMATION_POINT__COMPLEX_CONFIG_

显示更多

Map<String,Map<String,Map<String,String>>>

简单配置。

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__CLAIM_INFORMATION_POINT__SIMPLE_CONFIG_

显示更多

Map<String,Map<String,String>>

定义应保留在缓存中的条目限制

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATH_CACHE_MAX_ENTRIES

显示更多

整数

1000

定义条目应过期的毫秒数

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATH_CACHE_LIFESPAN

显示更多

long

30000

指定适配器应如何从服务器获取与应用程序中的路径关联的资源。如果为 true,则策略执行器将根据所请求的路径按需获取资源

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_LAZY_LOAD_PATHS

显示更多

布尔值

true

复杂配置。

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__CLAIM_INFORMATION_POINT__COMPLEX_CONFIG_

显示更多

Map<String,Map<String,Map<String,String>>>

简单配置。

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_PATHS__PATHS__CLAIM_INFORMATION_POINT__SIMPLE_CONFIG_

显示更多

Map<String,Map<String,String>>

指定应如何将范围映射到 HTTP 方法。如果设置为 true,则策略执行器将使用当前请求中的 HTTP 方法来检查是否应授予访问权限

环境变量:QUARKUS_KEYCLOAK__TENANT__POLICY_ENFORCER_HTTP_METHOD_AS_SCOPE

显示更多

布尔值

false

相关内容