OpenID Connect (OIDC)身份验证


Red Hat build of Quarkus 3.8

Red Hat Customer Content Services

摘要

本指南提供了对 OpenID Connect (OIDC)身份验证的深入了解,使用 bearer 令牌身份验证来保护服务应用程序、OIDC 授权代码流来保护 Web 应用程序,以及 OIDC 多租户,以支持多个 OIDC 供应商和流。

提供有关红帽构建的 Quarkus 文档的反馈

要报告错误或改进文档,请登录到 Red Hat JIRA 帐户并提交问题。如果您没有 Red Hat Jira 帐户,则会提示您创建一个帐户。

流程

  1. 单击以下链接 以创建 ticket
  2. Summary 中输入问题的简短描述。
  3. Description 中提供问题或功能增强的详细描述。包括一个指向文档中问题的 URL。
  4. Submit 创建问题,并将问题路由到适当的文档团队。

使开源包含更多

红帽致力于替换我们的代码、文档和 Web 属性中有问题的语言。我们从这四个术语开始:master、slave、黑名单和白名单。由于此项工作十分艰巨,这些更改将在即将推出的几个发行版本中逐步实施。详情请查看 CTO Chris Wright 的信息

第 1 章 OpenID Connect (OIDC) Bearer 令牌身份验证

通过使用 Quarkus OpenID Connect (OIDC)扩展,保护应用中对带有 Bearer 令牌身份验证的 Jakarta REST (以前称为 JAX-RS)端点的 HTTP 访问。

1.1. Quarkus 中的 Bearer 令牌身份验证机制概述

Quarkus 通过 Quarkus OpenID Connect (OIDC)扩展支持 Bearer 令牌身份验证机制。

bearer 令牌由 OIDC 和 OAuth 2.0 兼容授权服务器发布,如 Keycloak

bearer 令牌身份验证是根据 bearer 令牌存在和有效授权 HTTP 请求的过程。bearer 令牌提供有关调用主题的信息,用于确定是否可以访问 HTTP 资源。

下图显示了 Quarkus 中的 Bearer 令牌身份验证机制:

图 1.1. 带有单页应用程序的 Quarkus 中的 bearer 令牌身份验证机制

  1. Quarkus 服务从 OIDC 供应商检索验证密钥。验证密钥用于验证 bearer 访问令牌签名。
  2. Quarkus 用户访问单页应用程序(SPA)。
  3. 单页应用程序使用授权代码流来验证用户并从 OIDC 供应商检索令牌。
  4. 单页应用使用访问令牌从 Quarkus 服务检索服务数据。
  5. Quarkus 服务使用验证密钥验证 bearer 访问令牌签名,检查令牌到期日期和其他声明,允许请求在令牌有效时继续,并将服务响应返回到单页应用。
  6. 单页应用程序将同一数据返回到 Quarkus 用户。

图 1.2. 使用 Java 或命令行客户端的 Quarkus 中的 bearer 令牌身份验证机制

  1. Quarkus 服务从 OIDC 供应商检索验证密钥。验证密钥用于验证 bearer 访问令牌签名。
  2. 客户端使用 client_credentials,它需要客户端 ID 和 secret 或密码授权,这需要客户端 ID、secret、用户名和密码从 OIDC 供应商检索访问令牌。
  3. 客户端使用访问令牌从 Quarkus 服务检索服务数据。
  4. Quarkus 服务使用验证密钥验证 bearer 访问令牌签名,检查令牌到期日期和其他声明,允许请求在令牌有效时继续,并将服务响应返回给客户端。

如果您需要使用 OIDC 授权代码流验证和授权用户,请参阅 Quarkus OpenID Connect 授权代码流机制来保护 Web 应用程序 指南。另外,如果您使用 Keycloak 和 bearer 令牌,请参阅使用 Keycloak 的 Quarkus 来集中授权 指南。

要了解如何使用 OIDC Bearer 令牌身份验证来保护服务应用程序,请参阅以下教程:* 使用 OpenID Connect (OIDC)授权代码流保护 Web 应用程序

有关如何支持多个租户的详情,请参考使用 OpenID Connect Multi-Tenancy 的 Quarkus。

1.1.1. 访问 JWT 声明

如果需要访问 JWT 令牌声明,您可以注入 JsonWebToken

package org.acme.security.openid.connect;

import org.eclipse.microprofile.jwt.JsonWebToken;
import jakarta.inject.Inject;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

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

    @Inject
    JsonWebToken jwt;

    @GET
    @RolesAllowed("admin")
    @Produces(MediaType.TEXT_PLAIN)
    public String admin() {
        return "Access for subject " + jwt.getSubject() + " is granted";
    }
}
Copy to Clipboard Toggle word wrap

@ApplicationScoped@Singleton@RequestScoped 范围支持 JsonWebToken 注入。但是,如果单个声明被注入为简单类型,则需要使用 @RequestScoped。如需更多信息,请参阅 Quarkus "Using JWT RBAC" 指南中的 支持的注入范围 部分。

1.1.2. UserInfo

如果您必须从 OIDC UserInfo 端点请求 UserInfo JSON 对象,请设置 quarkus.oidc.authentication.user-info-required=true。请求发送到 OIDC 提供程序 UserInfo 端点,并且创建 io.quarkus.oidc.UserInfo (一个简单的 javax.json.JsonObject wrapper)对象。io.quarkus.oidc.UserInfo 可以作为 SecurityIdentity userinfo 属性注入或访问。

1.1.3. 配置元数据

当前租户的发现的 OpenID Connect 配置元数据io.quarkus.oidc.OidcConfigurationMetadata 表示,并可作为 SecurityIdentity configuration-metadata 属性注入或访问。

如果端点是 public,则默认租户的 OidcConfigurationMetadata 会被注入。

1.1.4. 令牌声明和安全身份角色

您可以从验证的 JWT 访问令牌映射 SecurityIdentity 角色,如下所示:

  • 如果设置了 quarkus.oidc.roles.role-claim-path 属性,并找到匹配的数组或字符串声明,则从这些声明中提取角色。例如,Customroles ,custom roles/array,scope,"http://namespace-qualified-custom-claim"/roles,"http://namespace-qualified-roles"
  • 如果有一个 声明可用,则使用其值。
  • 如果 realm_access/rolesresource_access/client_id/roles (其中 client_idquarkus.oidc.client-id 属性的值)声明可用,则使用其值。此检查支持 Keycloak 发布的令牌。

例如,以下 JWT 令牌具有一个复杂的 groups 声明,其中包含包含 角色的角色 数组:

{
    "iss": "https://server.example.com",
    "sub": "24400320",
    "upn": "jdoe@example.com",
    "preferred_username": "jdoe",
    "exp": 1311281970,
    "iat": 1311280970,
    "groups": {
        "roles": [
          "microprofile_jwt_user"
        ],
    }
}
Copy to Clipboard Toggle word wrap

您必须将 microprofile_jwt_user 角色映射到 SecurityIdentity 角色,并且您可以使用此配置: quarkus.oidc.roles.role-claim-path=groups/roles

如果令牌不透明(二进制),则使用来自远程令牌内省响应的 scope 属性。

如果 UserInfo 是角色的来源,则设置 quarkus.oidc.authentication.user-info-required=truequarkus.oidc.roles.source=userinfo,如需要设置 quarkus.oidc.roles.role-claim-path

此外,也可以使用自定义 SecurityIdentityAugmentor 来添加角色。如需更多信息,请参阅 Quarkus " Security tips and tricks" 指南中的 安全身份自定义 部分。

您还可以使用 HTTP 安全策略 将创建从令牌声明创建的 SecurityIdentity 角色映射到特定于部署的角色。

1.1.5. 令牌范围和 SecurityIdentity 权限

SecurityIdentity 权限以 io.quarkus.security.StringPermission 的形式映射,来自 角色源的 scope 参数,并使用相同的声明分隔符。

import java.util.List;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.eclipse.microprofile.jwt.Claims;
import org.eclipse.microprofile.jwt.JsonWebToken;

import io.quarkus.security.PermissionsAllowed;

@Path("/service")
public class ProtectedResource {

    @Inject
    JsonWebToken accessToken;

    @PermissionsAllowed("email") 
1

    @GET
    @Path("/email")
    public Boolean isUserEmailAddressVerifiedByUser() {
        return accessToken.getClaim(Claims.email_verified.name());
    }

    @PermissionsAllowed("orders_read") 
2

    @GET
    @Path("/order")
    public List<Order> listOrders() {
        return List.of(new Order(1));
    }

    public static class Order {
        String id;
        public Order() {
        }
        public Order(String id) {
            this.id = id;
        }
        public String getId() {
            return id;
        }
        public void setId() {
            this.id = id;
        }
    }
}
Copy to Clipboard Toggle word wrap
1
只有 OpenID Connect 范围 电子邮件 的请求才会被授予访问权限。
2
读访问权限仅限于具有 orders_read 范围的客户端请求。

有关 io.quarkus.security.PermissionsAllowed 注解的更多信息,请参阅"Authorization of web endpoint"指南中的 Permission 注解 部分。

1.1.6. 令牌验证和内省

如果令牌是 JWT 令牌,默认情况下,它通过来自本地 JsonWebKeySet 中的 JsonWebKey (JWK)密钥进行验证,从 OIDC 提供程序的 JWK 端点检索。令牌的密钥标识符(kid)标头值用于查找匹配的 JWK 键。如果本地没有匹配的 JWK 可用,则通过从 JWK 端点获取当前密钥集来刷新 JsonWebKeySetJsonWebKeySet 刷新只能在 quarkus.oidc.token.forced-jwk-refresh-interval 过期后重复。默认到期时间为 10 分钟。如果在刷新后没有匹配的 JWK,则 JWT 令牌将发送到 OIDC 提供程序的令牌内省端点。

如果令牌不透明,这意味着可以是二进制令牌或加密的 JWT 令牌,则始终发送到 OIDC 提供程序的令牌内省端点。

如果您仅使用 JWT 令牌,并且希望始终可用的 JsonWebKey,例如在刷新密钥集后,您必须禁用令牌内省,如以下示例所示:

quarkus.oidc.token.allow-jwt-introspection=false
quarkus.oidc.token.allow-opaque-token-introspection=false
Copy to Clipboard Toggle word wrap

在某些情况下,只有通过内省验证 JWT 令牌时,可以通过仅配置内省端点地址来强制进行。以下属性配置演示了如何使用 Keycloak 实现它的示例:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.discovery-enabled=false
# Token Introspection endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/tokens/introspect
quarkus.oidc.introspection-path=/protocol/openid-connect/tokens/introspect
Copy to Clipboard Toggle word wrap

远程强制 JWT 令牌内省有优缺点。优点是,您可以消除两个远程调用的需要:远程 OIDC 元数据发现调用,以及另一个远程调用来获取不使用的验证密钥。缺点是,您需要知道内省端点地址并手动配置。

另一种方法是允许 OIDC 元数据发现的默认选项,还需要只执行远程 JWT 内省,如下例所示:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.token.require-jwt-introspection-only=true
Copy to Clipboard Toggle word wrap

这种方法的一个优点是配置更简单且更易于理解。缺点是,远程 OIDC 元数据发现调用需要发现内省端点地址,即使不会获取验证密钥。

将创建 io.quarkus.oidc.TokenIntrospection,它是一个简单的 jakarta.json.JsonObject wrapper 对象。它可以作为 SecurityIdentity introspection 属性注入或访问,提供 JWT 或不透明令牌已成功内省。

1.1.7. 令牌内省和 UserInfo 缓存

所有不透明访问令牌都必须远程内省。有时,还必须内省 JWT 访问令牌。如果同时需要 UserInfo,则会在对 OIDC 提供程序的后续远程调用中使用相同的访问令牌。因此,如果需要 UserInfo,并且当前访问令牌不透明,会为每个此类令牌进行两个远程调用;一个远程调用来内省令牌,另一个用于获取 UserInfo。如果令牌是 JWT,则只需要对 get UserInfo 的单一远程调用,除非也必须内省。

对每个传入 bearer 或代码流访问令牌最多进行两个远程调用的成本有时可能会造成问题。

如果这是生产环境中的,请考虑在短时间内缓存令牌内省和 UserInfo 数据,例如 3 或 5 分钟。

quarkus-oidc 提供 quarkus.oidc.TokenIntrospectionCachequarkus.oidc.UserInfoCache 接口,可用于 @ApplicationScoped 缓存实现。使用 @ApplicationScoped 缓存实现存储和检索 quarkus.oidc.TokenIntrospection 和/或 quarkus.oidc.UserInfo 对象,如下例所示:

@ApplicationScoped
@Alternative
@Priority(1)
public class CustomIntrospectionUserInfoCache implements TokenIntrospectionCache, UserInfoCache {
...
}
Copy to Clipboard Toggle word wrap

每个 OIDC 租户都可以允许或拒绝其 quarkus.oidc.TokenIntrospection 数据、quarkus.oidc.UserInfo 数据,或使用布尔值 quarkus.oidc."tenant".allow-token-introspection-cachequarkus.oidc."tenant".allow-user-info-cache 属性的存储。

另外,quarkus-oidc 提供了一个基于内存的简单令牌缓存,它实现了 quarkus.oidc.TokenIntrospectionCachequarkus.oidc.UserInfoCache 接口。

您可以配置并激活默认的 OIDC 令牌缓存,如下所示:

# 'max-size' is 0 by default, so the cache can be activated by setting 'max-size' to a positive value:
quarkus.oidc.token-cache.max-size=1000
# 'time-to-live' specifies how long a cache entry can be valid for and will be used by a cleanup timer:
quarkus.oidc.token-cache.time-to-live=3M
# 'clean-up-timer-interval' is not set by default, so the cleanup timer can be activated by setting 'clean-up-timer-interval':
quarkus.oidc.token-cache.clean-up-timer-interval=1M
Copy to Clipboard Toggle word wrap

默认缓存使用令牌作为密钥,每个条目都可以具有 TokenIntrospectionUserInfo 或两者。它只会保留最大大小的条目数。如果在添加新条目时缓存已满,则会尝试通过删除单个过期条目来查找空格。另外,如果激活,清理计时器会定期检查过期的条目并删除它们。

您可以使用默认缓存实现试验或注册自定义缓存。

1.1.8. JSON Web 令牌声明验证

在验证 bearer JWT 令牌签名 并在 (exp)声明被检查后,将验证 iss (issuer)声明值。

默认情况下,iss claim 值与 issuer 属性进行比较,该属性可能已在已知的提供程序配置中发现。但是,如果设置了 quarkus.oidc.token.issuer 属性,则 iss claim 值会被与它进行比较。

在某些情况下,这是声明 验证可能无法正常工作。例如,如果发现的 issuer 属性包含内部 HTTP/IP 地址,而 令牌是 声明值包含外部 HTTP/IP 地址。或者,当发现的 issuer 属性包含模板租户变量时,但 令牌是 声明值具有完整的特定于租户的签发者值。

在这种情况下,请考虑通过设置 quarkus.oidc.token.issuer=any 来跳过签发者验证。只有没有其他选项时才跳过签发者验证:

  • 如果您使用 Keycloak,并观察由不同主机地址导致的签发者验证错误,请使用 KEYCLOAK_FRONTEND_URL 属性配置 Keycloak 以确保使用相同的主机地址。
  • 如果 iss 属性在多租户部署中特定于租户,请使用 SecurityIdentity tenant-id 属性来检查签发者在端点或自定义 Jakarta 过滤器中是否正确。例如:
import jakarta.inject.Inject;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;

import org.eclipse.microprofile.jwt.JsonWebToken;
import io.quarkus.oidc.OidcConfigurationMetadata;
import io.quarkus.security.identity.SecurityIdentity;

@Provider
public class IssuerValidator implements ContainerRequestFilter {
    @Inject
    OidcConfigurationMetadata configMetadata;

    @Inject JsonWebToken jwt;
    @Inject SecurityIdentity identity;

    public void filter(ContainerRequestContext requestContext) {
        String issuer = configMetadata.getIssuer().replace("{tenant-id}", identity.getAttribute("tenant-id"));
        if (!issuer.equals(jwt.getIssuer())) {
            requestContext.abortWith(Response.status(401).build());
        }
    }
}
Copy to Clipboard Toggle word wrap
注意

考虑使用 quarkus.oidc.token.audience 属性来验证令牌 aud (audience)声明值。

1.1.9. 单页应用程序

单页应用(SPA)通常使用 XMLHttpRequest(XHR)和 OIDC 提供程序提供的 JavaScript 实用程序代码,以获取 bearer 令牌来访问 Quarkus 服务 应用程序。

例如,如果使用 Keycloak,您可以使用 keycloak.js 验证用户并从 SPA 刷新过期的令牌:

<html>
<head>
    <title>keycloak-spa</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="http://localhost:8180/js/keycloak.js"></script>
    <script>
        var keycloak = new Keycloak();
        keycloak.init({onLoad: 'login-required'}).success(function () {
            console.log('User is now authenticated.');
        }).error(function () {
            window.location.reload();
        });
        function makeAjaxRequest() {
            axios.get("/api/hello", {
                headers: {
                    'Authorization': 'Bearer ' + keycloak.token
                }
            })
            .then( function (response) {
                console.log("Response: ", response.status);
            }).catch(function (error) {
                console.log('refreshing');
                keycloak.updateToken(5).then(function () {
                    console.log('Token refreshed');
                }).catch(function () {
                    console.log('Failed to refresh token');
                    window.location.reload();
                });
            });
    }
    </script>
</head>
<body>
    <button onclick="makeAjaxRequest()">Request</button>
</body>
</html>
Copy to Clipboard Toggle word wrap

1.1.10. 跨原始资源共享

如果您计划从在不同域上运行的单页应用中使用 OIDC 服务 应用程序,您必须配置跨原始资源共享(CORS)。如需更多信息,请参阅"Cross-origin 资源共享"指南中的 CORS 过滤器 部分。

1.1.11. 供应商端点配置

OIDC 服务 应用需要知道 OIDC 供应商的令牌、JsonWebKey (JWK)设置,以及可能的 UserInfo 和内省端点地址。

默认情况下,通过将 /.well-known/openid-configuration 路径添加到配置的 quarkus.oidc.auth-server-url 来发现它们。

或者,如果发现端点不可用,或者要在发现端点往返中保存,您可以禁用发现并使用相对路径值进行配置。例如:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.discovery-enabled=false
# Token endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/token
quarkus.oidc.token-path=/protocol/openid-connect/token
# JWK set endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/certs
quarkus.oidc.jwks-path=/protocol/openid-connect/certs
# UserInfo endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/userinfo
quarkus.oidc.user-info-path=/protocol/openid-connect/userinfo
# Token Introspection endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/tokens/introspect
quarkus.oidc.introspection-path=/protocol/openid-connect/tokens/introspect
Copy to Clipboard Toggle word wrap

1.1.12. 令牌传播

有关 bearer 访问令牌传播到下游服务的详情,请参考 Quarkus "OpenID Connect (OIDC)和 OAuth2 客户端和过滤器参考" 指南中的 Token propagation 部分。

1.1.13. OIDC 供应商客户端身份验证

当需要对 OIDC 供应商的远程请求时,使用 quarkus.oidc.runtime.OidcProviderClient。如果需要内省 Bearer 令牌,则 OidcProviderClient 必须向 OIDC 提供程序进行身份验证。有关支持的验证选项的更多信息,请参阅 Quarkus "OpenID Connect authorization code flow mechanism for protect web application" 指南中的 OIDC provider client authentication 部分。

1.1.14. 测试

注意

如果需要测试需要 Keycloak 授权的 Quarkus OIDC 服务端点,请按照 Test Keycloak 授权 部分操作。

您可以通过在测试项目中添加以下依赖项开始测试:

  • 使用 Maven:

    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>rest-assured</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-junit5</artifactId>
        <scope>test</scope>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    testImplementation("io.rest-assured:rest-assured")
    testImplementation("io.quarkus:quarkus-junit5")
    Copy to Clipboard Toggle word wrap
1.1.14.1. WireMock

在您的测试项目中添加以下依赖项:

  • 使用 Maven:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-test-oidc-server</artifactId>
        <scope>test</scope>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    testImplementation("io.quarkus:quarkus-test-oidc-server")
    Copy to Clipboard Toggle word wrap

准备 REST 测试端点并设置 application.properties。例如:

# keycloak.url is set by OidcWiremockTestResource
quarkus.oidc.auth-server-url=${keycloak.url}/realms/quarkus/
quarkus.oidc.client-id=quarkus-service-app
quarkus.oidc.application-type=service
Copy to Clipboard Toggle word wrap

最后,编写测试代码。例如:

import static org.hamcrest.Matchers.equalTo;

import java.util.Set;

import org.junit.jupiter.api.Test;

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.oidc.server.OidcWiremockTestResource;
import io.restassured.RestAssured;
import io.smallrye.jwt.build.Jwt;

@QuarkusTest
@QuarkusTestResource(OidcWiremockTestResource.class)
public class BearerTokenAuthorizationTest {

    @Test
    public void testBearerToken() {
        RestAssured.given().auth().oauth2(getAccessToken("alice", Set.of("user")))
            .when().get("/api/users/me")
            .then()
            .statusCode(200)
            // The test endpoint returns the name extracted from the injected `SecurityIdentity` principal.
            .body("userName", equalTo("alice"));
    }

    private String getAccessToken(String userName, Set<String> groups) {
        return Jwt.preferredUserName(userName)
                .groups(groups)
                .issuer("https://server.example.com")
                .audience("https://service.example.com")
                .sign();
    }
}
Copy to Clipboard Toggle word wrap

quarkus-test-oidc-server 扩展包含 JSON Web 密钥(JWK)格式的签名 RSA 私钥文件,并使用 smallrye.jwt.sign.key.location 配置属性指向它。它允许您使用 no-argument sign () 操作为令牌签名。

使用 OidcWiremockTestResource 测试 quarkus-oidc 服务 应用程序提供了最佳覆盖,因为即使通信通道针对 WireMock HTTP stub 进行了测试。如果您需要使用 WireMock stubs 运行测试,它还没有被 OidcWiremockTestResource 支持,您可以将 WireMockServer 实例注入测试类,如下例所示:

注意

OidcWiremockTestResource 无法针对 Docker 容器使用 @QuarkusIntegrationTest,因为运行测试的 JVM 中运行 WireMock 服务器,这无法从运行 Quarkus 应用的 Docker 容器访问。

package io.quarkus.it.keycloak;

import static com.github.tomakehurst.wiremock.client.WireMock.matching;
import static org.hamcrest.Matchers.equalTo;

import org.junit.jupiter.api.Test;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.oidc.server.OidcWireMock;
import io.restassured.RestAssured;

@QuarkusTest
public class CustomOidcWireMockStubTest {

    @OidcWireMock
    WireMockServer wireMockServer;

    @Test
    public void testInvalidBearerToken() {
        wireMockServer.stubFor(WireMock.post("/auth/realms/quarkus/protocol/openid-connect/token/introspect")
                .withRequestBody(matching(".*token=invalid_token.*"))
                .willReturn(WireMock.aResponse().withStatus(400)));

        RestAssured.given().auth().oauth2("invalid_token").when()
                .get("/api/users/me/bearer")
                .then()
                .statusCode(401)
                .header("WWW-Authenticate", equalTo("Bearer"));
    }
}
Copy to Clipboard Toggle word wrap

1.1.15. OidcTestClient

如果您使用 SaaS OIDC 供应商,如 Auth0,并希望针对测试(开发)域运行测试,或者针对远程 Keycloak 测试域运行测试,如果您已经配置了 quarkus.oidc.auth-server-url,您可以使用 OidcTestClient

例如,您有以下配置:

%test.quarkus.oidc.auth-server-url=https://dev-123456.eu.auth0.com/
%test.quarkus.oidc.client-id=test-auth0-client
%test.quarkus.oidc.credentials.secret=secret
Copy to Clipboard Toggle word wrap

要启动,请添加相同的依赖项 quarkus-test-oidc-server,如 WireMock 部分所述。

接下来,按如下方式编写测试代码:

package org.acme;

import org.junit.jupiter.api.AfterAll;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

import java.util.Map;

import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.oidc.client.OidcTestClient;

@QuarkusTest
public class GreetingResourceTest {

    static OidcTestClient oidcTestClient = new OidcTestClient();

    @AfterAll
    public static void close() {
        oidcTestClient.close();
    }

    @Test
    public void testHelloEndpoint() {
        given()
          .auth().oauth2(getAccessToken("alice", "alice"))
          .when().get("/hello")
          .then()
             .statusCode(200)
             .body(is("Hello, Alice"));
    }

    private String getAccessToken(String name, String secret) {
        return oidcTestClient.getAccessToken(name, secret,
            Map.of("audience", "https://dev-123456.eu.auth0.com/api/v2/",
	           "scope", "profile"));
    }
}
Copy to Clipboard Toggle word wrap

此测试代码使用来自 test Auth0 域的 密码 授权获取令牌,该密码使用客户端 id test-auth0-client 注册了应用,并使用密码 alice 创建用户 alice。要使测试正常工作,test Auth0 应用必须启用 密码 授权。这个示例代码还演示了如何传递额外的参数。对于 Auth0,它们是 audiencescope 参数。

1.1.15.1. Keycloak 的 dev Services

针对 Keycloak 进行集成测试的首选方法是 Keycloak 的 Dev Services用于 Keycloak 的 dev Services 将启动并初始化测试容器。然后,它将创建一个 quarkus realm 和 quarkus-app 客户端(secret secret),并添加 alice (admin user roles)和 bob (用户角色)用户,其中所有这些属性都可以自定义。

首先,添加以下依赖项,它提供实用程序类 io.quarkus.test.keycloak.client.KeycloakTestClient,您可以用于测试获取访问令牌:

  • 使用 Maven:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-test-keycloak-server</artifactId>
        <scope>test</scope>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    testImplementation("io.quarkus:quarkus-test-keycloak-server")
    Copy to Clipboard Toggle word wrap

接下来,准备 application.properties 配置文件。您可以从一个空的 application.properties 文件开始,因为 Keycloak 的 Dev Services 注册 quarkus.oidc.auth-server-url,并将它指向正在运行的测试容器,quarkus.oidc.client-id=quarkus-app, 和 quarkus.oidc.credentials.secret=secret

但是,如果您已配置了所需的 quarkus-oidc 属性,则您只需要将 quarkus.oidc.auth-server-url 与 'Dev Services for Keycloak' 的 prod 配置集关联,如下例所示:

%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
Copy to Clipboard Toggle word wrap

如果在运行测试前必须将自定义域文件导入到 Keycloak 中,请为 Keycloak 配置 Dev Services,如下所示:

%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.keycloak.devservices.realm-path=quarkus-realm.json
Copy to Clipboard Toggle word wrap

最后,编写您的测试,它将在 JVM 模式中执行,如下例所示:

以 JVM 模式执行的测试示例:

package org.acme.security.openid.connect;

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.keycloak.client.KeycloakTestClient;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;

@QuarkusTest
public class BearerTokenAuthenticationTest {

    KeycloakTestClient keycloakClient = new KeycloakTestClient();

    @Test
    public void testAdminAccess() {
        RestAssured.given().auth().oauth2(getAccessToken("alice"))
                .when().get("/api/admin")
                .then()
                .statusCode(200);
        RestAssured.given().auth().oauth2(getAccessToken("bob"))
                .when().get("/api/admin")
                .then()
                .statusCode(403);
    }

    protected String getAccessToken(String userName) {
        return keycloakClient.getAccessToken(userName);
    }
}
Copy to Clipboard Toggle word wrap

以原生模式执行的测试示例:

package org.acme.security.openid.connect;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class NativeBearerTokenAuthenticationIT extends BearerTokenAuthenticationTest {
}
Copy to Clipboard Toggle word wrap

有关为 Keycloak 初始化和配置 Dev Services 的更多信息,请参阅 Keycloak 的 Dev Services 指南。

1.1.15.2. 本地公钥

您可以使用本地内联公钥来测试 quarkus-oidc 服务 应用程序,如下例所示:

quarkus.oidc.client-id=test
quarkus.oidc.public-key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9xnQIDAQAB

smallrye.jwt.sign.key.location=/privateKey.pem
Copy to Clipboard Toggle word wrap

要生成 JWT 令牌,请从 Quarkus 存储库中的 integration-tests/oidc-tenancy 复制 privateKey.pem,并使用与上一 WireMock 部分中类似的测试代码。如果需要,您可以使用自己的测试密钥。

与 WireMock 方法相比,这种方法提供有限的覆盖范围。例如,不包括远程通信代码。

1.1.15.3. TestSecurity 注解

您可以使用 @TestSecurity@OidcSecurity 注释来测试 服务 应用程序端点代码(取决于以下注入之一或全部三个):

  • JsonWebToken
  • UserInfo
  • OidcConfigurationMetadata

首先,添加以下依赖项:

  • 使用 Maven:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-test-security-oidc</artifactId>
        <scope>test</scope>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    testImplementation("io.quarkus:quarkus-test-security-oidc")
    Copy to Clipboard Toggle word wrap

按照以下示例中所述编写测试代码:

import static org.hamcrest.Matchers.is;
import org.junit.jupiter.api.Test;
import io.quarkus.test.common.http.TestHTTPEndpoint;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.quarkus.test.security.oidc.Claim;
import io.quarkus.test.security.oidc.ConfigMetadata;
import io.quarkus.test.security.oidc.OidcSecurity;
import io.quarkus.test.security.oidc.OidcConfigurationMetadata;
import io.quarkus.test.security.oidc.UserInfo;
import io.restassured.RestAssured;

@QuarkusTest
@TestHTTPEndpoint(ProtectedResource.class)
public class TestSecurityAuthTest {

    @Test
    @TestSecurity(user = "userOidc", roles = "viewer")
    public void testOidc() {
        RestAssured.when().get("test-security-oidc").then()
                .body(is("userOidc:viewer"));
    }

    @Test
    @TestSecurity(user = "userOidc", roles = "viewer")
    @OidcSecurity(claims = {
            @Claim(key = "email", value = "user@gmail.com")
    }, userinfo = {
            @UserInfo(key = "sub", value = "subject")
    }, config = {
            @ConfigMetadata(key = "issuer", value = "issuer")
    })
    public void testOidcWithClaimsUserInfoAndMetadata() {
        RestAssured.when().get("test-security-oidc-claims-userinfo-metadata").then()
                .body(is("userOidc:viewer:user@gmail.com:subject:issuer"));
    }

}
Copy to Clipboard Toggle word wrap

在这个代码示例中使用的 ProtectedResource 类可能类似如下:

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

import io.quarkus.oidc.OidcConfigurationMetadata;
import io.quarkus.oidc.UserInfo;
import io.quarkus.security.Authenticated;

import org.eclipse.microprofile.jwt.JsonWebToken;

@Path("/service")
@Authenticated
public class ProtectedResource {

    @Inject
    JsonWebToken accessToken;
    @Inject
    UserInfo userInfo;
    @Inject
    OidcConfigurationMetadata configMetadata;

    @GET
    @Path("test-security-oidc")
    public String testSecurityOidc() {
        return accessToken.getName() + ":" + accessToken.getGroups().iterator().next();
    }

    @GET
    @Path("test-security-oidc-claims-userinfo-metadata")
    public String testSecurityOidcWithClaimsUserInfoMetadata() {
        return accessToken.getName() + ":" + accessToken.getGroups().iterator().next()
                + ":" + accessToken.getClaim("email")
                + ":" + userInfo.getString("sub")
                + ":" + configMetadata.get("issuer");
    }
}
Copy to Clipboard Toggle word wrap

您必须始终使用 @TestSecurity 注释。其 user 属性返回为 JsonWebToken.getName (),其 roles 属性返回为 JsonWebToken.getGroups ()@OidcSecurity 注释是可选的,您可以使用它来设置额外的令牌声明和 UserInfoOidcConfigurationMetadata 属性。另外,如果配置了 quarkus.oidc.token.issuer 属性,它将用作 OidcConfigurationMetadata issuer 属性值。

如果使用不透明令牌,您可以测试它们,如下例所示:

import static org.hamcrest.Matchers.is;
import org.junit.jupiter.api.Test;
import io.quarkus.test.common.http.TestHTTPEndpoint;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.quarkus.test.security.oidc.OidcSecurity;
import io.quarkus.test.security.oidc.TokenIntrospection;
import io.restassured.RestAssured;

@QuarkusTest
@TestHTTPEndpoint(ProtectedResource.class)
public class TestSecurityAuthTest {

    @Test
    @TestSecurity(user = "userOidc", roles = "viewer")
    @OidcSecurity(introspectionRequired = true,
        introspection = {
            @TokenIntrospection(key = "email", value = "user@gmail.com")
        }
    )
    public void testOidcWithClaimsUserInfoAndMetadata() {
        RestAssured.when().get("test-security-oidc-claims-userinfo-metadata").then()
                .body(is("userOidc:viewer:userOidc:viewer"));
    }

}
Copy to Clipboard Toggle word wrap

在这个代码示例中使用的 ProtectedResource 类可能类似如下:

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

import io.quarkus.oidc.TokenIntrospection;
import io.quarkus.security.Authenticated;
import io.quarkus.security.identity.SecurityIdentity;

@Path("/service")
@Authenticated
public class ProtectedResource {

    @Inject
    SecurityIdentity securityIdentity;
    @Inject
    TokenIntrospection introspection;

    @GET
    @Path("test-security-oidc-opaque-token")
    public String testSecurityOidcOpaqueToken() {
        return securityIdentity.getPrincipal().getName() + ":" + securityIdentity.getRoles().iterator().next()
            + ":" + introspection.getString("username")
            + ":" + introspection.getString("scope")
            + ":" + introspection.getString("email");
    }
}
Copy to Clipboard Toggle word wrap

@TestSecurityuserroles 属性作为 TokenIntrospectionusernamescope 属性提供。使用 io.quarkus.test.security.oidc.TokenIntrospection 来添加额外的内省响应属性,如电子邮件 等等。

提示

@TestSecurity@OidcSecurity 可以合并到 meta-annotation 中,如下例所示:

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD })
    @TestSecurity(user = "userOidc", roles = "viewer")
    @OidcSecurity(introspectionRequired = true,
        introspection = {
            @TokenIntrospection(key = "email", value = "user@gmail.com")
        }
    )
    public @interface TestSecurityMetaAnnotation {

    }
Copy to Clipboard Toggle word wrap

如果多个测试方法必须使用同一组安全设置,这特别有用。

1.1.16. 检查日志中的错误

要查看有关令牌验证错误的更多详细信息,请启用 io.quarkus.oidc.runtime.OidcProviderTRACE 级别日志记录:

quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".min-level=TRACE
Copy to Clipboard Toggle word wrap

要查看有关 OidcProvider 客户端初始化错误的更多详细信息,请启用 io.quarkus.oidc.runtime.OidcRecorderTRACE 级别日志记录,如下所示:

quarkus.log.category."io.quarkus.oidc.runtime.OidcRecorder".level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.OidcRecorder".min-level=TRACE
Copy to Clipboard Toggle word wrap

1.1.17. 对 OIDC 供应商的外部和内部访问

与自动发现或配置了 quarkus.oidc.auth-server-url 内部 URL 的 URL 相比,OIDC 供应商和其他端点可能具有不同的 HTTP (S) URL。例如,假设您的 SPA 从外部令牌端点地址获取令牌,并将其发送到 Quarkus 作为 bearer 令牌。在这种情况下,端点可能会报告签发者验证失败。

在这种情况下,如果您使用 Keycloak,使用 KEYCLOAK_FRONTEND_URL 系统属性将其设置为外部可访问的基本 URL。如果使用其他 OIDC 供应商,请参阅您的供应商文档。

1.1.18. 使用 client-id 属性

quarkus.oidc.client-id 属性标识请求当前 bearer 令牌的 OIDC 客户端。OIDC 客户端可以是在浏览器中运行的 SPA 应用程序,也可以是 Quarkus Web-app 机密客户端应用程序将访问令牌传播到 Quarkus 服务 应用程序。

如果服务 应用预期远程内省令牌,则需要此属性,这始终是不透明令牌的情况。此属性是可选的,用于本地 JSON Web Token (JWT)验证。

即使端点不需要访问远程内省端点,也鼓励设置 quarkus.oidc.client-id 属性。这是因为当设置了 client-id 时,它可用于验证令牌受众。当令牌验证失败时,它也将包含在日志中,从而提高了签发给特定客户端的令牌的可追溯性,并在较长时间内进行分析。

例如,如果您的 OIDC 供应商设置了令牌受众,请考虑以下配置模式:

# Set client-id
quarkus.oidc.client-id=quarkus-app
# Token audience claim must contain 'quarkus-app'
quarkus.oidc.token.audience=${quarkus.oidc.client-id}
Copy to Clipboard Toggle word wrap

如果您设置了 quarkus.oidc.client-id,但您的端点不需要远程访问 OIDC 供应商端点之一(整数、令牌获取等),请不要使用 quarkus.oidc.credentials 或类似属性设置客户端 secret,因为它不会被使用。

注意

Quarkus web-app 应用程序总是需要 quarkus.oidc.client-id 属性。

1.2. HTTP 请求完成后进行身份验证

有时,如果没有活跃的 HTTP 请求上下文时,必须创建给定令牌的 SecurityIdentityquarkus-oidc 扩展提供 io.quarkus.oidc.TenantIdentityProvider,将令牌转换为 SecurityIdentity 实例。例如,在 HTTP 请求完成后必须验证令牌时,其中一个情况是在您使用 Vert.x 事件总线 处理消息时。以下示例在不同的 CDI 请求上下文中使用"product-order"消息。因此,注入的 SecurityIdentity 无法正确代表验证的身份,并且是匿名的。

package org.acme.quickstart.oidc;

import static jakarta.ws.rs.core.HttpHeaders.AUTHORIZATION;

import jakarta.inject.Inject;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import io.vertx.core.eventbus.EventBus;

@Path("order")
public class OrderResource {

    @Inject
    EventBus eventBus;

    @POST
    public void order(String product, @HeaderParam(AUTHORIZATION) String bearer) {
        String rawToken = bearer.substring("Bearer ".length()); 
1

        eventBus.publish("product-order", new Product(product, rawToken));
    }

    public static class Product {
         public String product;
         public String customerAccessToken;
         public Product() {
         }
         public Product(String product, String customerAccessToken) {
             this.product = product;
             this.customerAccessToken = customerAccessToken;
         }
    }
}
Copy to Clipboard Toggle word wrap
1
此时,在禁用主动身份验证时,不会验证令牌。
package org.acme.quickstart.oidc;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import io.quarkus.oidc.AccessTokenCredential;
import io.quarkus.oidc.TenantFeature;
import io.quarkus.oidc.TenantIdentityProvider;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.vertx.ConsumeEvent;
import io.smallrye.common.annotation.Blocking;

@ApplicationScoped
public class OrderService {

    @TenantFeature("tenantId")
    @Inject
    TenantIdentityProvider identityProvider;

    @Inject
    TenantIdentityProvider defaultIdentityProvider; 
1


    @Blocking
    @ConsumeEvent("product-order")
    void processOrder(Product product) {
        AccessTokenCredential tokenCredential = new AccessTokenCredential(product.customerAccessToken);
        SecurityIdentity securityIdentity = identityProvider.authenticate(tokenCredential).await().indefinitely(); 
2

        ...
    }

}
Copy to Clipboard Toggle word wrap
1
对于默认租户,TenantFeature qualifier 是可选的。
2
执行令牌验证,并将令牌转换为 SecurityIdentity
注意

在 HTTP 请求过程中使用供应商时,可以解析租户配置,如 使用 OpenID Connect Multi-Tenancy 指南中所述。但是,如果没有活跃的 HTTP 请求时,您必须明确选择带有 io.quarkus.oidc.TenantFeature qualifier 的租户。

警告

目前不支持 动态租户配置解析。需要动态租户的身份验证将失败。

1.3. OIDC 请求过滤器

您可以通过注册一个或多个 OidcRequestFilter 实现(可以更新或添加新的请求标头)来过滤 Quarkus 向 OIDC 供应商发出的 OIDC 请求,以及日志请求。如需更多信息,请参阅 OIDC 请求过滤器

1.4. 参考

使用 Quarkus OpenID Connect (OIDC)扩展来保护带有 Bearer 令牌身份验证的 Jakarta REST 应用。bearer 令牌由 OIDC 和 OAuth 2.0 兼容授权服务器发布,如 Keycloak

有关 OIDC Bearer 令牌身份验证的更多信息,请参阅 Quarkus OpenID Connect (OIDC) Bearer 令牌身份验证 指南。

如果要使用 OIDC 授权代码流身份验证保护 Web 应用程序,请参阅 OpenID Connect 授权代码流机制来保护 Web 应用程序 指南。

2.1. 先决条件

要完成本指南,您需要:

2.2. 架构

本例演示了如何构建提供两个端点的简单微服务:

  • /api/users/me
  • /api/admin

这些端点受到保护,只有在客户端发送 bearer 令牌与请求时才能访问,该令牌必须有效(如签名、到期和受众)并由微服务信任。

Keycloak 服务器发出 bearer 令牌,并代表签发令牌的主题。由于它是 OAuth 2.0 授权服务器,因此令牌也会代表用户引用客户端。

具有有效令牌的任何用户都可以访问 /api/users/me 端点。作为响应,它会返回一个 JSON 文档,其中包含从令牌中信息中获取的用户详细信息。

/api/admin 端点通过 RBAC 进行保护(Role-Based Access Control),只有具有 admin 角色的用户才能访问。在这个端点中,@RolesAllowed 注释用于声明性地强制实施访问约束。

2.3. 解决方案

按照下一小节中的说明,并逐步创建应用程序步骤。您也可以直接转至完整的示例。

您可以通过运行命令 git clone https://github.com/quarkusio/quarkus-quickstarts.git -b 3.8 来克隆 Git 存储库,也可以下载 归档

解决方案位于 security-openid-connect-quickstart 目录中

2.4. 创建 Maven 项目

您可以使用 oidc 扩展创建新的 Maven 项目,也可以将扩展添加到现有的 Maven 项目中。完成以下任一命令:

要创建新的 Maven 项目,请使用以下命令:

  • 使用 Quarkus CLI:

    quarkus create app org.acme:security-openid-connect-quickstart \
        --extension='oidc,resteasy-reactive-jackson' \
        --no-code
    cd security-openid-connect-quickstart
    Copy to Clipboard Toggle word wrap

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

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

  • 使用 Maven:

    mvn io.quarkus.platform:quarkus-maven-plugin:3.8.5:create \
        -DprojectGroupId=org.acme \
        -DprojectArtifactId=security-openid-connect-quickstart \
        -Dextensions='oidc,resteasy-reactive-jackson' \
        -DnoCode
    cd security-openid-connect-quickstart
    Copy to Clipboard Toggle word wrap

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

对于 Windows 用户:

  • 如果使用 cmd,(不要使用反向斜杠 \ 并将所有内容放在同一行中)
  • 如果使用 Powershell,则双引号中的 wrap -D 参数,如 "-DprojectArtifactId=security-openid-connect-quickstart"

如果您已经配置了 Quarkus 项目,您可以通过在项目基本目录中运行以下命令来将 oidc 扩展添加到项目中:

  • 使用 Quarkus CLI:

    quarkus extension add oidc
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw quarkus:add-extension -Dextensions='oidc'
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew addExtension --extensions='oidc'
    Copy to Clipboard Toggle word wrap

这将在您的构建文件中添加以下内容:

  • 使用 Maven:

    <dependency>
       <groupId>io.quarkus</groupId>
       <artifactId>quarkus-oidc</artifactId>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    implementation("io.quarkus:quarkus-oidc")
    Copy to Clipboard Toggle word wrap

2.5. 编写应用程序

  1. 按照以下示例所示,实现 /api/users/me 端点,它是一个常规 Jakarta REST 资源:

    package org.acme.security.openid.connect;
    
    import jakarta.annotation.security.RolesAllowed;
    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 securityIdentity;
    
        @GET
        @Path("/me")
        @RolesAllowed("user")
        @NoCache
        public User me() {
            return new User(securityIdentity);
        }
    
        public static class User {
    
            private final String userName;
    
            User(SecurityIdentity securityIdentity) {
                this.userName = securityIdentity.getPrincipal().getName();
            }
    
            public String getUserName() {
                return userName;
            }
        }
    }
    Copy to Clipboard Toggle word wrap
  2. 实现 /api/admin 端点,如下例所示:

    package org.acme.security.openid.connect;
    
    import jakarta.annotation.security.RolesAllowed;
    import jakarta.ws.rs.GET;
    import jakarta.ws.rs.Path;
    import jakarta.ws.rs.Produces;
    import jakarta.ws.rs.core.MediaType;
    
    @Path("/api/admin")
    public class AdminResource {
    
        @GET
        @RolesAllowed("admin")
        @Produces(MediaType.TEXT_PLAIN)
        public String admin() {
            return "granted";
        }
    }
    Copy to Clipboard Toggle word wrap
    注意

    本例中的主要区别在于,@RolesAllowed 注释仅用于验证仅授予 admin 角色的用户才能访问端点。

@RequestScoped@ApplicationScoped 上下文都支持 SecurityIdentity 注入。

2.6. 配置应用程序

  • 通过在 src/main/resources/application.properties 文件中设置以下配置属性来配置 Quarkus OpenID Connect (OIDC)扩展。

    %prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
    quarkus.oidc.client-id=backend-service
    quarkus.oidc.credentials.secret=secret
    
    # Tell Dev Services for Keycloak to import the realm file
    # This property is not effective when running the application in JVM or native modes
    
    quarkus.keycloak.devservices.realm-path=quarkus-realm.json
    Copy to Clipboard Toggle word wrap

其中:

  • %prod.quarkus.oidc.auth-server-url 设置 OpenID Connect (OIDC)服务器的基本 URL。%prod. 配置集前缀可确保 Keycloak 的 Dev Services 在开发(dev)模式下运行应用程序时启动容器。有关更多信息,请参阅 在 dev mode 部分中运行应用
  • quarkus.oidc.client-id 设置用于标识应用程序的客户端 ID。
  • quarkus.oidc.credentials.secret 设置客户端 secret,该 secret 由 client_secret_basic 身份验证方法使用。

如需更多信息,请参阅 Quarkus OpenID Connect (OIDC)配置属性 指南。

2.7. 启动并启用 Keycloak 服务器

  1. realm 配置文件放在 classpath (target/classes 目录)上,以便在 dev 模式中运行时自动导入。如果您已构建了 完整的解决方案,则不需要执行此操作,在这种情况下,此域文件会添加到构建期间的 classpath 中。

    注意

    当您以 dev 模式运行应用程序时,不要启动 Keycloak 服务器 ; Keycloak 的 Dev Services 将启动一个容器。有关更多信息,请参阅 在 dev mode 部分中运行应用

  2. 要启动 Keycloak 服务器,您可以使用 Docker 运行以下命令:

    docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev
    Copy to Clipboard Toggle word wrap
    • 其中 keycloak.version 设置为 24.0.0 或更高版本。
  3. 您可以在 localhost:8180 访问您的 Keycloak 服务器。
  4. 要访问 Keycloak 管理控制台,请使用以下登录凭证以 admin 用户身份登录:

    • 用户名:admin
    • Password: admin
  5. 从上游 community 存储库导入 realm 配置文件,以创建新域。

如需更多信息,请参阅关于 创建和配置新域的 Keycloak 文档

2.8. 在 dev 模式下运行应用程序

  1. 要在 dev 模式下运行应用程序,请运行以下命令:

    • 使用 Quarkus CLI:

      quarkus dev
      Copy to Clipboard Toggle word wrap
    • 使用 Maven:

      ./mvnw quarkus:dev
      Copy to Clipboard Toggle word wrap
    • 使用 Gradle:

      ./gradlew --console=plain quarkusDev
      Copy to Clipboard Toggle word wrap
  2. 打开 Dev UI,您可以在 /q/dev-ui 中找到。然后,在 OpenID Connect 卡中,点 Keycloak 供应商 链接。
  3. 当提示登录到 OpenID Connect Dev UI 提供的 单个页面 应用程序时,请执行以下步骤:

    • alice 身份(密码: alice)登录,其具有 用户角色

      • 访问 /api/admin 会返回 403 状态代码。
      • 访问 /api/users/me 会返回 200 状态代码。
    • 注销,然后重新以 admin 身份(密码: admin)登录,其具有 admin用户角色

      • 访问 /api/admin 会返回 200 状态代码。
      • 访问 /api/users/me 会返回 200 状态代码。

2.9. 在 JVM 模式下运行应用程序

使用 dev 模式时,您可以将应用作为标准 Java 应用运行。

  1. 编译应用程序:

    • 使用 Quarkus CLI:

      quarkus build
      Copy to Clipboard Toggle word wrap
    • 使用 Maven:

      ./mvnw install
      Copy to Clipboard Toggle word wrap
    • 使用 Gradle:

      ./gradlew build
      Copy to Clipboard Toggle word wrap
  2. 运行应用程序:

    java -jar target/quarkus-app/quarkus-run.jar
    Copy to Clipboard Toggle word wrap

2.10. 以原生模式运行应用程序

您可以在不进行任何修改的情况下,将此演示编译为原生模式。这意味着您不再需要在生产环境中安装 JVM。运行时技术包含在生成的二进制中,并经过优化,以便以最少的资源运行。

编译时间需要一些时间,因此默认禁用此步骤。

  1. 通过启用 原生 配置集来再次构建应用程序:

    • 使用 Quarkus CLI:

      quarkus build --native
      Copy to Clipboard Toggle word wrap
    • 使用 Maven:

      ./mvnw install -Dnative
      Copy to Clipboard Toggle word wrap
    • 使用 Gradle:

      ./gradlew build -Dquarkus.package.type=native
      Copy to Clipboard Toggle word wrap
  2. 等待一段时间后,您直接运行以下二进制文件:

    ./target/security-openid-connect-quickstart-1.0.0-SNAPSHOT-runner
    Copy to Clipboard Toggle word wrap

2.11. 测试应用

有关以 dev 模式测试应用程序的信息,请参阅前面的在 dev mode 部分中运行该应用

您可以使用 curl 来测试以 JVM 或原生模式启动的应用程序。

  • 因为应用程序使用 Bearer 令牌身份验证,您必须首先从 Keycloak 服务器获取访问令牌来访问应用程序资源:
export access_token=$(\
    curl --insecure -X POST http://localhost: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' | jq --raw-output '.access_token' \
 )
Copy to Clipboard Toggle word wrap

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

curl -v -X GET \
  http://localhost:8080/api/users/me \
  -H "Authorization: Bearer "$access_token
Copy to Clipboard Toggle word wrap
  • 只有具有 admin 角色的用户才能访问 http://localhost:8080/api/admin 端点。如果您尝试使用之前发布的访问令牌访问此端点,您可以从服务器获得 403 响应。
curl -v -X GET \
   http://localhost:8080/api/admin \
   -H "Authorization: Bearer "$access_token
Copy to Clipboard Toggle word wrap
  • 要访问 admin 端点,获取 admin 用户的令牌:
export access_token=$(\
    curl --insecure -X POST http://localhost:8180/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' \
 )
Copy to Clipboard Toggle word wrap

有关编写依赖于 Keycloak 的 Dev 服务 的集成测试的详情,请参考 "OpenID Connect (OIDC) Bearer 令牌身份验证" 指南中的 Dev Services for Keycloak 部分。

2.12. 参考

要保护 Web 应用程序,您可以使用 Quarkus OIDC 扩展提供的行业标准 OpenID Connect (OIDC)授权代码流机制。

3.1. OIDC 授权代码流机制概述

Quarkus OpenID Connect (OIDC)扩展可以使用 OIDC 兼容授权服务器支持的 OIDC 授权代码流机制(如 Keycloak )来保护应用程序 HTTP 端点。

授权代码流机制通过将 Web 应用程序重定向到 OIDC 供应商(如 Keycloak)来验证用户,以登录。身份验证后,OIDC 供应商将使用授权代码将用户重新重定向到应用程序,确认身份验证是否成功。然后,应用程序使用 ID 令牌的 OIDC 供应商(代表经过身份验证的用户)、访问令牌和刷新令牌交换此代码,以授权用户访问应用程序。

下图显示了 Quarkus 中的授权代码流机制。

图 3.1. Quarkus 中的授权代码流机制

  1. Quarkus 用户请求访问 Quarkus web-app 应用程序。
  2. Quarkus web-app 将用户重定向到授权端点,即用于身份验证的 OIDC 供应商。
  3. OIDC 供应商将用户重定向到登录和验证提示。
  4. 在提示符处,用户输入其用户凭据。
  5. OIDC 供应商验证输入的用户凭证,如果成功,请发出授权代码,并使用作为查询参数包括的代码重定向到 Quarkus web-app。
  6. Quarkus web-app 使用 ID、访问和刷新令牌的 OIDC 供应商交换此授权代码。

授权代码流已完成,Quarkus web-app 使用发布的令牌来访问用户的信息,并为该用户授予相关基于角色的访问控制。发布以下令牌:

  • ID 令牌 : Quarkus web-app 应用使用 ID 令牌中的用户信息,使经过身份验证的用户能够安全地登录,并提供对 Web 应用程序的基于角色的访问控制。
  • 访问令牌 : Quarkus web-app 可以使用访问令牌访问 UserInfo API 来获取有关经过身份验证的用户的附加信息,或将其传播到另一个端点。
  • 刷新令牌:(可选)如果 ID 和访问令牌过期,则 Quarkus web-app 可以使用刷新令牌获取新的 ID 和访问令牌。

另请参阅 OIDC 配置属性 参考指南。

要了解如何使用 OIDC 授权代码流机制保护 Web 应用程序,请参阅使用 OIDC 授权代码流保护 Web 应用程序

如果要使用 OIDC Bearer 令牌身份验证来保护服务应用程序,请参阅 OIDC Bearer 令牌身份验证

有关如何支持多个租户的详情,请参考 使用 OpenID Connect Multi-Tenancy

3.2. 使用授权代码流机制

3.2.1. 配置对 OIDC 供应商端点的访问

OIDC web-app 应用需要 OIDC 供应商的授权、令牌、JsonWebKey (JWK)集的 URL,以及 UserInfo、introspection 和 end-session (RP-initiated logout)端点。

按照惯例,通过将 /.well-known/openid-configuration 路径添加到配置的 quarkus.oidc.auth-server-url 来发现它们。

或者,如果发现端点不可用,或者您希望减少发现端点往返,您可以禁用端点发现并配置相对路径值。例如:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.discovery-enabled=false
# Authorization endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/auth
quarkus.oidc.authorization-path=/protocol/openid-connect/auth
# Token endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/token
quarkus.oidc.token-path=/protocol/openid-connect/token
# JWK set endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/certs
quarkus.oidc.jwks-path=/protocol/openid-connect/certs
# UserInfo endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/userinfo
quarkus.oidc.user-info-path=/protocol/openid-connect/userinfo
# Token Introspection endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/token/introspect
quarkus.oidc.introspection-path=/protocol/openid-connect/token/introspect
# End-session endpoint: http://localhost:8180/realms/quarkus/protocol/openid-connect/logout
quarkus.oidc.end-session-path=/protocol/openid-connect/logout
Copy to Clipboard Toggle word wrap

有些 OIDC 供应商支持元数据发现,但不要返回授权代码流完成或支持应用程序功能所需的所有端点 URL 值,如用户注销。要临时解决这个问题,您可以在本地配置缺少的端点 URL 值,如下例所示:

# Metadata is auto-discovered but it does not return an end-session endpoint URL

quarkus.oidc.auth-server-url=http://localhost:8180/oidcprovider/account

# Configure the end-session URL locally.
# It can be an absolute or relative (to 'quarkus.oidc.auth-server-url') address
quarkus.oidc.end-session-path=logout
Copy to Clipboard Toggle word wrap

如果 URL 无法用于本地 Quarkus 端点,并且需要更具体的值,则可以使用同样的配置来覆盖发现的端点 URL。例如,支持全局和特定于应用程序的最终用户会话端点的供应商会返回一个全局最终用户会话 URL,如 http://localhost:8180/oidcprovider/account/global-logout。此 URL 将从当前登录的用户的所有应用中注销用户。但是,如果要求是当前应用程序只将用户从特定应用程序注销,您可以通过设置 quarkus.oidc.end-session=logout 参数来覆盖全局 end-session URL。

3.2.1.1. OIDC 供应商客户端身份验证

OIDC 供应商通常需要在与 OIDC 端点交互时识别和验证应用程序。quarkus OIDC,特别是 quarkus.oidc.runtime.OidcProviderClient 类,当必须刷新或内省授权代码时,向 OIDC 供应商进行身份验证。

通常,当授权到 OIDC 供应商时,为给定应用程序定义客户端 ID 和客户端 secret。所有 OIDC 客户端身份验证 选项都被支持。例如:

client_secret_basic 示例:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.secret=mysecret
Copy to Clipboard Toggle word wrap

或者:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.client-secret.value=mysecret
Copy to Clipboard Toggle word wrap

以下示例显示了从 凭证供应商 检索的 secret:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app

# This is a key which will be used to retrieve a secret from the map of credentials returned from CredentialsProvider
quarkus.oidc.credentials.client-secret.provider.key=mysecret-key
# Set it only if more than one CredentialsProvider can be registered
quarkus.oidc.credentials.client-secret.provider.name=oidc-credentials-provider
Copy to Clipboard Toggle word wrap

client_secret_post示例

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.client-secret.value=mysecret
quarkus.oidc.credentials.client-secret.method=post
Copy to Clipboard Toggle word wrap

client_secret_jwt 示例,其签名算法是 HS256:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.jwt.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow
Copy to Clipboard Toggle word wrap

client_secret_jwt 示例,其中 secret 从 凭证提供程序 检索:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app

# This is a key which will be used to retrieve a secret from the map of credentials returned from CredentialsProvider
quarkus.oidc.credentials.jwt.secret-provider.key=mysecret-key
# Set it only if more than one CredentialsProvider can be registered
quarkus.oidc.credentials.jwt.secret-provider.name=oidc-credentials-provider
Copy to Clipboard Toggle word wrap

使用 PEM 密钥文件的 private_key_jwt 示例,签名算法为 RS256:。

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.jwt.key-file=privateKey.pem
Copy to Clipboard Toggle word wrap

使用密钥存储文件的 private_key_jwt 示例,签名算法为 RS256:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.jwt.key-store-file=keystore.jks
quarkus.oidc.credentials.jwt.key-store-password=mypassword
quarkus.oidc.credentials.jwt.key-password=mykeypassword

# Private key alias inside the keystore
quarkus.oidc.credentials.jwt.key-id=mykeyAlias
Copy to Clipboard Toggle word wrap

使用 client_secret_jwtprivate_key_jwt 身份验证方法可确保客户端 secret 没有发送到 OIDC 供应商,因此避免了被 'man-in-the-middle' 攻击所截获的 secret 的风险。

3.2.1.1.1. 其他 JWT 身份验证选项

如果使用 client_secret_jwtprivate_key_jwt 或 Apple post_jwt 身份验证方法,您可以自定义 JWT 签名算法、密钥标识符、使用者、主题和签发者。例如:

# private_key_jwt client authentication

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.jwt.key-file=privateKey.pem

# This is a token key identifier 'kid' header - set it if your OIDC provider requires it:
# Note if the key is represented in a JSON Web Key (JWK) format with a `kid` property, then
# using 'quarkus.oidc.credentials.jwt.token-key-id' is not necessary.
quarkus.oidc.credentials.jwt.token-key-id=mykey

# Use RS512 signature algorithm instead of the default RS256
quarkus.oidc.credentials.jwt.signature-algorithm=RS512

# The token endpoint URL is the default audience value, use the base address URL instead:
quarkus.oidc.credentials.jwt.audience=${quarkus.oidc-client.auth-server-url}

# custom subject instead of the client id:
quarkus.oidc.credentials.jwt.subject=custom-subject

# custom issuer instead of the client id:
quarkus.oidc.credentials.jwt.issuer=custom-issuer
Copy to Clipboard Toggle word wrap
3.2.1.1.2. Apple POST JWT

Apple OIDC 供应商使用 client_secret_post 方法,其中 secret 是使用 private_key_jwt 身份验证方法生成的 JWT,但使用 Apple 帐户特定的签发者和主题声明。

在 Quarkus Security 中,quarkus-oidc 支持非标准 client_secret_post_jwt 身份验证方法,如下所示:

# Apple provider configuration sets a 'client_secret_post_jwt' authentication method
quarkus.oidc.provider=apple

quarkus.oidc.client-id=${apple.client-id}
quarkus.oidc.credentials.jwt.key-file=ecPrivateKey.pem
quarkus.oidc.credentials.jwt.token-key-id=${apple.key-id}
# Apple provider configuration sets ES256 signature algorithm

quarkus.oidc.credentials.jwt.subject=${apple.subject}
quarkus.oidc.credentials.jwt.issuer=${apple.issuer}
Copy to Clipboard Toggle word wrap
3.2.1.1.3. Mutual TLS (mTLS)

有些 OIDC 供应商可能需要客户端作为 mutual TLS 身份验证过程的一部分进行身份验证。

以下示例演示了如何配置 quarkus-oidc 以支持 mTLS

quarkus.oidc.tls.verification=certificate-validation

# Keystore configuration
quarkus.oidc.tls.key-store-file=client-keystore.jks
quarkus.oidc.tls.key-store-password=${key-store-password}

# Add more keystore properties if needed:
#quarkus.oidc.tls.key-store-alias=keyAlias
#quarkus.oidc.tls.key-store-alias-password=keyAliasPassword

# Truststore configuration
quarkus.oidc.tls.trust-store-file=client-truststore.jks
quarkus.oidc.tls.trust-store-password=${trust-store-password}
# Add more truststore properties if needed:
#quarkus.oidc.tls.trust-store-alias=certAlias
Copy to Clipboard Toggle word wrap
3.2.1.1.4. POST 查询

有些供应商(如 Strava OAuth2 供应商 )需要发布客户端凭证作为 HTTP POST 查询参数:

quarkus.oidc.provider=strava
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.client-secret.value=mysecret
quarkus.oidc.credentials.client-secret.method=query
Copy to Clipboard Toggle word wrap
3.2.1.2. 内省端点身份验证

有些 OIDC 供应商需要使用基本身份验证以及与 client_idclient_secret 不同的凭证进行身份验证。如果您之前已将安全身份验证配置为支持 client_secret_basicclient_secret_post 客户端身份验证方法,如 OIDC 供应商 客户端身份验证部分中所述,您可能需要应用额外的配置,如下所示。

如果必须内省令牌,并且需要内省特定于内省端点的身份验证机制,您可以配置 quarkus-oidc,如下所示:

quarkus.oidc.introspection-credentials.name=introspection-user-name
quarkus.oidc.introspection-credentials.secret=introspection-user-secret
Copy to Clipboard Toggle word wrap
3.2.1.3. OIDC 请求过滤器

您可以通过注册一个或多个 OidcRequestFilter 实现(可以更新或添加新的请求标头)来过滤 Quarkus 向 OIDC 供应商发出的 OIDC 请求,也可以记录请求。

例如:

package io.quarkus.it.keycloak;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.arc.Unremovable;
import io.quarkus.oidc.common.OidcRequestContextProperties;
import io.quarkus.oidc.common.OidcRequestFilter;
import io.vertx.mutiny.core.buffer.Buffer;
import io.vertx.mutiny.ext.web.client.HttpRequest;

@ApplicationScoped
@Unremovable
public class OidcTokenRequestCustomizer implements OidcRequestFilter {
    @Override
    public void filter(HttpRequest<Buffer> request, Buffer buffer, OidcRequestContextProperties contextProps) {
        OidcConfigurationMetadata metadata = contextProps.get(OidcConfigurationMetadata.class.getName()); 
1

        // Metadata URI is absolute, request URI value is relative
        if (metadata.getTokenUri().endsWith(request.uri())) { 
2

            request.putHeader("TokenGrantDigest", calculateDigest(buffer.toString()));
        }
    }
    private String calculateDigest(String bodyString) {
        // Apply the required digest algorithm to the body string
    }
}
Copy to Clipboard Toggle word wrap
1
get OidcConfigurationMetadata,其中包含所有支持的 OIDC 端点地址。
2
使用 OidcConfigurationMetadata 只过滤对 OIDC 令牌端点的请求。

或者,您可以使用 OidcRequestFilter.Endpoint enum 将此过滤器仅应用到令牌端点请求:

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.arc.Unremovable;
import io.quarkus.oidc.common.OidcEndpoint;
import io.quarkus.oidc.common.OidcEndpoint.Type;
import io.quarkus.oidc.common.OidcRequestContextProperties;
import io.quarkus.oidc.common.OidcRequestFilter;
import io.vertx.mutiny.core.buffer.Buffer;
import io.vertx.mutiny.ext.web.client.HttpRequest;

@ApplicationScoped
@Unremovable
@OidcEndpoint(value = Type.DISCOVERY) 
1

public class OidcDiscoveryRequestCustomizer implements OidcRequestFilter {

    @Override
    public void filter(HttpRequest<Buffer> request, Buffer buffer, OidcRequestContextProperties contextProps) {
        request.putHeader("Discovery", "OK");
    }
}
Copy to Clipboard Toggle word wrap
1
将这个过滤器限制为只针对 OIDC 发现端点的请求。
3.2.1.4. 重定向至 OIDC 供应商

当用户重定向到 OIDC 供应商以进行身份验证时,重定向 URL 包含一个 redirect_uri 查询参数,该参数表示在身份验证完成后必须重定向到的供应商。在我们的情形中,这是 Quarkus 应用程序。

默认情况下,quarkus 将此参数设置为当前应用程序请求 URL。例如,如果用户试图访问 http://localhost:8080/service/1 上的 Quarkus 服务端点,则 redirect_uri 参数被设置为 http://localhost:8080/service/1。同样,如果请求 URL 是 http://localhost:8080/service/2,则 redirect_uri 参数被设置为 http://localhost:8080/service/2

有些 OIDC 供应商要求将 redirect_uri 的值与给定应用程序的值相同,例如 http://localhost:8080/service/callback,用于所有重定向 URL。在这种情况下,必须设置 quarkus.oidc.authentication.redirect-path 属性。例如,quarkus.oidc.authentication.redirect-path=/service/callback,Quarkus 会将 redirect_uri 参数设置为绝对 URL,如 http://localhost:8080/service/callback,它都相同,无论当前请求 URL 都相同。

如果设置了 quarkus.oidc.authentication.redirect-path,但您需要在用户重定向到唯一回调 URL 后恢复原始请求 URL,例如 http://localhost:8080/service/callback,将 quarkus.oidc.authentication.restore-path-after-redirect 属性设置为 true。这将恢复请求 URL,如 http://localhost:8080/service/1

3.2.1.5. 自定义身份验证请求

默认情况下,只有 response_type (设置为 代码)、scope (设置为 openid)、client_idredirect_uri、以及 status 属性在用户重定向到时传递给 OIDC 供应商的授权端点。

您可以使用 quarkus.oidc.authentication.extra-params 添加更多属性。例如,有些 OIDC 供应商可能会选择返回授权代码作为重定向 URI 片段的一部分,这会中断身份验证过程。以下示例演示了如何解决这个问题:

quarkus.oidc.authentication.extra-params.response_mode=query
Copy to Clipboard Toggle word wrap
3.2.1.6. 自定义身份验证错误响应

当用户重定向到 OIDC 授权端点以进行身份验证时,如果需要,授权 Quarkus 应用程序,这个重定向请求可能会失败,例如,当重定向 URI 中包含无效的范围时。在这种情况下,供应商会将用户重新重定向到 Quarkus,并带有 errorerror_description 参数,而不是预期的 代码 参数。

例如,当重定向到提供程序的无效范围或其他无效参数时,可能会发生这种情况。

在这种情况下,默认会返回 HTTP 401 错误。但是,您可以请求调用自定义公共错误端点,以返回更用户友好的 HTML 错误页面。要做到这一点,请设置 quarkus.oidc.authentication.error-path 属性,如下例所示:

quarkus.oidc.authentication.error-path=/error
Copy to Clipboard Toggle word wrap

确保属性以正斜杠(/)字符开头,并且路径相对于当前端点的基本 URI。例如,如果设为 '/error',并且当前请求 URI 为 https://localhost:8080/callback?error=invalid_scope,则向 https://localhost:8080/error?error=invalid_scope 发出最终重定向。

重要

若要防止用户重定向到此页面,需要重新验证,请确保此错误端点为公共资源。

3.2.2. 访问授权数据

您可以通过不同的方式访问授权信息。

3.2.2.1. 访问 ID 和访问令牌

OIDC 代码身份验证机制在授权代码流期间获取三个令牌: ID 令牌、访问令牌和刷新令牌。

ID 令牌始终是一个 JWT 令牌,代表使用 JWT 声明进行用户身份验证。您可以使用它来发出 OIDC 端点、用户名以及名为 声明 的其他信息。您可以使用 IdToken qualifier 注入 JsonWebToken 来访问 ID 令牌声明:

import jakarta.inject.Inject;
import org.eclipse.microprofile.jwt.JsonWebToken;
import io.quarkus.oidc.IdToken;
import io.quarkus.security.Authenticated;

@Path("/web-app")
@Authenticated
public class ProtectedResource {

    @Inject
    @IdToken
    JsonWebToken idToken;

    @GET
    public String getUserName() {
        return idToken.getName();
    }
}
Copy to Clipboard Toggle word wrap

OIDC web-app 应用程序通常使用访问令牌代表当前登录的用户访问其他端点。您可以访问原始访问令牌,如下所示:

import jakarta.inject.Inject;
import org.eclipse.microprofile.jwt.JsonWebToken;
import io.quarkus.oidc.AccessTokenCredential;
import io.quarkus.security.Authenticated;

@Path("/web-app")
@Authenticated
public class ProtectedResource {

    @Inject
    JsonWebToken accessToken;

    // or
    // @Inject
    // AccessTokenCredential accessTokenCredential;

    @GET
    public String getReservationOnBehalfOfUser() {
        String rawAccessToken = accessToken.getRawToken();
        //or
        //String rawAccessToken = accessTokenCredential.getToken();

        // Use the raw access token to access a remote endpoint.
        // For example, use RestClient to set this token as a `Bearer` scheme value of the HTTP `Authorization` header:
        // `Authorization: Bearer rawAccessToken`.
        return getReservationfromRemoteEndpoint(rawAccesstoken);
    }
}
Copy to Clipboard Toggle word wrap
注意

如果发布到 Quarkus web-app 应用的访问令牌是不透明的,并且无法解析到 JsonWebToken,或者应用程序需要内内容,则使用 AccessTokenCredential

@RequestScoped@ApplicationScoped 上下文都支持 JsonWebTokenAccessTokenCredential 注入。

quarkus OIDC 使用刷新令牌来刷新当前的 ID 和访问令牌,作为其 会话管理 过程的一部分。

3.2.2.2. 用户信息

如果 ID 令牌没有提供有关当前经过身份验证的用户的足够信息,您可以从 UserInfo 端点获取更多信息。设置 quarkus.oidc.authentication.user-info-required=true 属性,从 OIDC UserInfo 端点请求 UserInfo JSON 对象。

使用通过授权代码授权响应返回的访问令牌将向 OIDC 提供程序 UserInfo 端点发送请求,以及一个 io.quarkus.oidc.UserInfo (一个简单的 jakarta.json.JsonObject wrapper)对象被创建。io.quarkus.oidc.UserInfo 可以作为 SecurityIdentity userinfo 属性注入或访问。

3.2.2.3. 访问 OIDC 配置信息

当前租户的发现的 OpenID Connect 配置元数据io.quarkus.oidc.OidcConfigurationMetadata 表示,并可作为 SecurityIdentity configuration-metadata 属性注入或访问。

如果端点是 public,则默认租户的 OidcConfigurationMetadata 会被注入。

3.2.2.4. 映射令牌声明和 SecurityIdentity 角色

角色从验证令牌映射到 SecurityIdentity 角色的方式与为 Bearer 令牌 的方式相同。唯一的区别是 ID 令牌 默认用作角色的来源。

注意

如果使用 Keycloak,请为 ID 令牌设置 microprofile-jwt 客户端范围,使其包含 声明。如需更多信息,请参阅 Keycloak 服务器管理指南

但是,根据您的 OIDC 供应商,角色可能会存储在访问令牌或用户信息中。

如果访问令牌包含角色,并且此访问令牌不应传播到下游端点,则设置 quarkus.oidc.roles.source=accesstoken

如果 UserInfo 是角色的来源,则设置 quarkus.oidc.roles.source=userinfo,如果需要,quarkus.oidc.roles.role-claim-path

另外,您还可以使用自定义 SecurityIdentityAugmentor 来添加角色。如需更多信息,请参阅安全身份管理 自定义。您还可以使用 HTTP 安全策略 将创建从令牌声明创建的 SecurityIdentity 角色映射到特定于部署的角色。

3.2.3. 确保令牌和身份验证数据的有效性

身份验证过程的一个核心部分是确保信息的信任链和有效性。这可以通过确保令牌可以被信任来实现。

3.2.3.1. 令牌验证和内省

OIDC 授权代码流令牌的验证过程遵循 Bearer 令牌身份验证令牌验证和内省逻辑。如需更多信息,请参阅"Quarkus OpenID Connect (OIDC) Bearer 令牌身份验证"指南中的令牌验证和内省部分。https://docs.redhat.com/en/documentation/red_hat_build_of_quarkus/3.8/html/openid_connect_oidc_authentication/security-oidc-bearer-token-authentication#bearer-token-token-verification-introspection

注意

使用 Quarkus web-app 应用程序时,默认只验证 IdToken,因为访问令牌没有用于访问当前的 Quarkus web-app 端点,并旨在传播到预期此访问令牌的服务。如果您希望访问令牌包含访问当前 Quarkus 端点所需的角色(quarkus.oidc.roles.source=accesstoken),则会验证它。

3.2.3.2. 令牌内省和 UserInfo 缓存

代码流访问令牌不会被内省,除非它们应当是角色的来源。但是,它们将用于获取 UserInfo。如果令牌内省、UserInfo 或两者都需要,则需要一个或多个带有代码流访问令牌的远程调用。

有关使用默认令牌缓存或注册自定义缓存实现的更多信息,请参阅 令牌内省和用户Info 缓存

3.2.3.3. JSON Web 令牌声明验证

有关声明验证的详情,包括 iss (issuer)声明,请参阅 JSON Web 令牌声明验证 部分。如果 web-app 应用请求访问令牌验证,它适用于 ID 令牌以及 JWT 格式的访问令牌验证。

代码 交换的证明密钥 (PKCE)可最大程度降低授权代码拦截器的风险。

虽然 PKCE 是公共 OIDC 客户端的主要重要性,如在浏览器中运行的 SPA 脚本,但它还可以提供对 Quarkus OIDC web-app 应用程序的额外保护。使用 PKCE 时,Quarkus OIDC web-app 应用程序充当机密 OIDC 客户端,这些客户端可以安全地存储客户端 secret,并使用它来交换令牌的代码。

您可以使用 quarkus.oidc.authentication.pkce-required 属性和 32 个字符的 secret 为 OIDC web-app 端点启用 PKCE 代码验证器,如下例所示:

quarkus.oidc.authentication.pkce-required=true
quarkus.oidc.authentication.state-secret=eUk1p7UB3nFiXZGUXi0uph1Y9p34YhBU
Copy to Clipboard Toggle word wrap

如果您已有 32 个字符的客户端 secret,则不需要设置 quarkus.oidc.authentication.pkce-secret 属性,除非您更喜欢使用不同的 secret 密钥。如果没有配置此 secret,且在客户端 secret 小于 16 个字符时,无法自动生成此 secret。

当用户使用 code_challenge 查询参数重定向到 OIDC 供应商时,需要加密随机生成的 PKCE code_verifier。当用户重定向到 Quarkus 时,code_verifier 会解密,并发送到令牌端点,代码、客户端 secret 和其他参数来完成代码交换。如果 code_verifierSHA256 摘要与身份验证请求过程中提供的 code_challenge 不匹配,则供应商将失败。

3.2.4. 处理和控制身份验证生命周期

身份验证的另一个重要要求是确保会话基于的数据是最新的,而不需要用户为每个请求进行身份验证。在有些情况下,明确请求 logout 事件。使用以下关键点查找保护 Quarkus 应用程序的正确平衡:

3.2.4.1. Cookie

OIDC 适配器使用 Cookie 来保留会话、代码流和超时状态。这个状态是控制身份验证数据生命周期的关键元素。

使用 quarkus.oidc.authentication.cookie-path 属性来确保当您访问具有重叠或不同根的受保护的资源时,可以看到相同的 Cookie。例如:

  • /index.html and /web-app/service
  • /web-app/service1 and /web-app/service2
  • /web-app1/service and /web-app2/service

默认情况下,quarkus.oidc.authentication.cookie-path 被设置为 /,但如果需要,您可以将它改为更具体的路径,例如 /web-app

要动态设置 Cookie 路径,请配置 quarkus.oidc.authentication.cookie-path-header 属性。设置 quarkus.oidc.authentication.cookie-path-header 属性。例如,要使用 'X-Forwarded-Prefix' HTTP 标头的值动态设置 Cookie 路径,请将 属性配置为 quarkus.oidc.authentication.cookie-path-header=X-Forwarded-Prefix

如果设置了 quarkus.oidc.authentication.cookie-path-header,但当前请求中没有配置的 HTTP 标头,则会检查 quarkus.oidc.authentication.cookie-path

如果您的应用程序在多个域中部署,请设置 quarkus.oidc.authentication.cookie-domain 属性,以便会话 Cookie 对所有受保护的 Quarkus 服务可见。例如,如果您在以下两个域中部署了 Quarkus 服务,您必须将 quarkus.oidc.authentication.cookie-domain 属性设置为 company.net

  • https://whatever.wherever.company.net/
  • https://another.address.company.net/
3.2.4.2. 会话 Cookie 和默认 TokenStateManager

OIDC CodeAuthenticationMechanism 使用默认的 io.quarkus.oidc.TokenStateManager 接口实现,以保留授权代码中返回的 ID、访问和刷新令牌,或在加密会话 Cookie 中刷新授权响应。

它使 Quarkus OIDC 端点完全无状态,建议遵循此策略来实现最佳的可扩展性结果。

有关令牌存储的替代方法,请参阅 Session cookie 和 custom TokenStateManager 部分。这对于那些希望自定义解决方案进行令牌状态管理的理想选择,特别是当标准服务器端存储不符合您的特定要求时。

您可以配置默认的 TokenStateManager,以避免在会话 Cookie 中保存访问令牌,并只保留 ID 和刷新令牌或单个 ID 令牌。

只有在端点需要执行以下操作时才需要访问令牌:

  • 检索 UserInfo
  • 使用这个访问令牌访问下游服务
  • 使用与访问令牌关联的角色,这些角色会被默认检查

在这种情况下,使用 quarkus.oidc.token-state-manager.strategy 属性来配置令牌状态策略,如下所示:

Expand
to…​将属性设置为 …​

只保留 ID 和刷新令牌

quarkus.oidc.token-state-manager.strategy=id-refresh-tokens

仅保留 ID 令牌

quarkus.oidc.token-state-manager.strategy=id-token

如果您所选的会话 Cookie 策略组合了令牌并生成大于 4KB 的大型会话 Cookie 值,则一些浏览器可能无法处理此类 Cookie 大小。当 ID、访问和刷新令牌是 JWT 令牌且所选策略为 keep-all-tokens 时,或者在策略 id-refresh-token 时使用 ID 和刷新令牌会出现这种情况。要临时解决这个问题,您可以设置 quarkus.oidc.token-state-manager.split-tokens=true 来为每个令牌创建一个唯一的会话令牌。

默认 TokenStateManager 会加密令牌,然后再将其存储在会话 Cookie 中。以下示例演示了如何将其配置为分割令牌并加密它们:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app
quarkus.oidc.token-state-manager.split-tokens=true
quarkus.oidc.token-state-manager.encryption-secret=eUk1p7UB3nFiXZGUXi0uph1Y9p34YhBU
Copy to Clipboard Toggle word wrap

令牌加密 secret 必须至少为 32 个字符。如果没有配置此密钥,则 quarkus.oidc.credentials.secretquarkus.oidc.credentials.jwt.secret 将会被哈希来创建加密密钥。

如果 Quarkus 使用以下身份验证方法之一向 OIDC 供应商进行身份验证,请配置 quarkus.oidc.token-state-manager.encryption-secret 属性:

  • mTLS
  • private_key_jwt,其中使用私有 RSA 或 EC 密钥为 JWT 令牌签名

否则,会生成一个随机密钥,如果 Quarkus 应用程序在管理请求的多个 pod 在云中运行,则可能会造成问题。

您可以通过设置 quarkus.oidc.token-state-manager.encryption-required=false 来禁用会话 Cookie 中的令牌加密。

3.2.4.3. 会话 Cookie 和自定义 TokenStateManager

如果要自定义令牌与会话 Cookie 关联的方式,请将自定义 io.quarkus.oidc.TokenStateManager 实现注册为 @ApplicationScoped CDI bean。

例如,您可能想要将令牌保留在缓存集群中,且只有一个密钥存储在会话 Cookie 中。请注意,如果您需要在多个微服务节点上提供令牌,这种方法可能会带来一些挑战。

以下是一个简单的示例:

package io.quarkus.oidc.test;

import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Alternative;
import jakarta.inject.Inject;

import io.quarkus.oidc.AuthorizationCodeTokens;
import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.TokenStateManager;
import io.quarkus.oidc.runtime.DefaultTokenStateManager;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
@Alternative
@Priority(1)
public class CustomTokenStateManager implements TokenStateManager {

    @Inject
    DefaultTokenStateManager tokenStateManager;

    @Override
    public Uni<String> createTokenState(RoutingContext routingContext, OidcTenantConfig oidcConfig,
            AuthorizationCodeTokens sessionContent, TokenStateManager.CreateTokenStateRequestContext requestContext) {
        return tokenStateManager.createTokenState(routingContext, oidcConfig, sessionContent, requestContext)
                .map(t -> (t + "|custom"));
    }

    @Override
    public Uni<AuthorizationCodeTokens> getTokens(RoutingContext routingContext, OidcTenantConfig oidcConfig,
            String tokenState, TokenStateManager.GetTokensRequestContext requestContext) {
        if (!tokenState.endsWith("|custom")) {
            throw new IllegalStateException();
        }
        String defaultState = tokenState.substring(0, tokenState.length() - 7);
        return tokenStateManager.getTokens(routingContext, oidcConfig, defaultState, requestContext);
    }

    @Override
    public Uni<Void> deleteTokens(RoutingContext routingContext, OidcTenantConfig oidcConfig, String tokenState,
            TokenStateManager.DeleteTokensRequestContext requestContext) {
        if (!tokenState.endsWith("|custom")) {
            throw new IllegalStateException();
        }
        String defaultState = tokenState.substring(0, tokenState.length() - 7);
        return tokenStateManager.deleteTokens(routingContext, oidcConfig, defaultState, requestContext);
    }
}
Copy to Clipboard Toggle word wrap

有关将令牌存储在加密会话 Cookie 中的默认 TokenStateManager 的详情,请参考 Session cookie 和 default TokenStateManager

3.2.4.4. 退出和过期

身份验证信息过期的方法有两种:令牌过期且没有续订或显式退出操作。

我们从明确注销操作开始。

3.2.4.4.1. user-initiated logout

用户可以通过向 Quarkus 端点注销路径发送请求,该路径使用 quarkus.oidc.logout.path 属性来请求注销。例如,如果端点地址为 https://application.com/webapp,并且 quarkus.oidc.logout.path 设置为 /logout,则必须将 logout 请求发送到 https://application.com/webapp/logout。

此注销请求将启动一个 RP-initiated logout。用户将被重定向到 OIDC 供应商以注销,并要求他们确认注销是否确实是正常的。

在注销完成后,用户将返回到端点 post-logout 页面,并且设置了 quarkus.oidc.logout.post-logout-path 属性。例如,如果端点地址为 https://application.com/webapp,并且 quarkus.oidc.logout.post-logout-path 设置为 /signin,则用户将返回到 https://application.com/webapp/signin。https://application.com/webapp/signin 请注意,此 URI 必须注册为 OIDC 供应商中的有效的 post_logout_redirect_uri

如果设置了 quarkus.oidc.logout.post-logout-path,则会创建一个 q_post_logout cookie,并将匹配的 state 查询参数添加到注销重定向 URI 中,OIDC 供应商会在注销完成后返回此状态。建议 Quarkus web-app 应用程序检查 state 查询参数是否与 q_post_logout cookie 的值匹配,例如在 Jakarta REST 过滤器中。

请注意,在使用 OpenID Connect Multi-Tenancy 时,cookie 名称会有所不同。例如,它将被命名为 q_post_logout_tenant_1,用于具有 tenant_1 ID 的租户,以此类推。

以下是如何配置 Quarkus 应用程序以启动注销流程的示例:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=frontend
quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app

quarkus.oidc.logout.path=/logout
# Logged-out users should be returned to the /welcome.html site which will offer an option to re-login:
quarkus.oidc.logout.post-logout-path=/welcome.html

# Only the authenticated users can initiate a logout:
quarkus.http.auth.permission.authenticated.paths=/logout
quarkus.http.auth.permission.authenticated.policy=authenticated

# All users can see the Welcome page:
quarkus.http.auth.permission.public.paths=/welcome.html
quarkus.http.auth.permission.public.policy=permit
Copy to Clipboard Toggle word wrap

您可能还希望将 quarkus.oidc.authentication.cookie-path 设置为对所有应用程序资源通用的路径值,本例中为 /。如需更多信息,请参阅 Cookies 部分。

注意

有些 OIDC 供应商不支持 RP-initiated logout 规格,且不会返回 OpenID Connect 已知的 end_session_endpoint 元数据属性。但是,这不是 Quarkus 的问题,因为此类 OIDC 供应商的特定注销机制仅在如何命名 logout URL 查询参数时有所不同。

根据 RP-initiated logout 规格,quarkus.oidc.logout.post-logout-path 属性表示为 post_logout_redirect_uri 查询参数,它不被不支持此规格的供应商识别。

您可以使用 quarkus.oidc.logout.post-logout-url-param 来临时解决这个问题。您还可以使用 quarkus.oidc.logout.extra-params 添加请求更多注销查询参数。例如,以下是如何使用 Auth0 支持注销:

quarkus.oidc.auth-server-url=https://dev-xxx.us.auth0.com
quarkus.oidc.client-id=redacted
quarkus.oidc.credentials.secret=redacted
quarkus.oidc.application-type=web-app

quarkus.oidc.tenant-logout.logout.path=/logout
quarkus.oidc.tenant-logout.logout.post-logout-path=/welcome.html

# Auth0 does not return the `end_session_endpoint` metadata property. Instead, you must configure it:
quarkus.oidc.end-session-path=v2/logout
# Auth0 will not recognize the 'post_logout_redirect_uri' query parameter so ensure it is named as 'returnTo':
quarkus.oidc.logout.post-logout-uri-param=returnTo

# Set more properties if needed.
# For example, if 'client_id' is provided, then a valid logout URI should be set as the Auth0 Application property, without it - as Auth0 Tenant property:
quarkus.oidc.logout.extra-params.client_id=${quarkus.oidc.client-id}
Copy to Clipboard Toggle word wrap
3.2.4.4.2. back-channel logout

OIDC 供应商可以使用身份验证数据强制注销所有应用程序。这称为 back-channel logout。在这种情况下,OIDC 将调用每个应用程序中的一个特定 URL 来触发该退出。

OIDC 供应商使用 Back-channel logout 从当前用户登录的所有应用程序注销,绕过用户代理。

您可以将 Quarkus 配置为支持 Back-channel logout,如下所示:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=frontend
quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app

quarkus.oidc.logout.backchannel.path=/back-channel-logout
Copy to Clipboard Toggle word wrap

absolute back-channel logout URL 通过向当前端点 URL 添加 quarkus.oidc.back-channel-logout.path 来计算,例如 http://localhost:8080/back-channel-logout。您需要在 OIDC 供应商的管理控制台中配置此 URL。

如果您的 OIDC 供应商没有在当前注销令牌中设置到期声明,您还需要为退出令牌验证配置令牌 age 属性。例如,设置 quarkus.oidc.token.age=10S,以确保自注销令牌的 iat (在)时间后没有超过 10 秒。

3.2.4.4.3. front-channel logout

您可以使用 Front-channel logout 直接从用户代理注销当前用户,例如其浏览器。它与 Back-channel logout 类似,但注销步骤由用户代理(如浏览器)执行,而不是在 OIDC 供应商在后台执行。这个选项很少被使用。

您可以配置 Quarkus 以支持 Front-channel logout,如下所示:

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=frontend
quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app

quarkus.oidc.logout.frontchannel.path=/front-channel-logout
Copy to Clipboard Toggle word wrap

此路径将与当前请求的路径进行比较,如果这些路径匹配,用户将被注销。

3.2.4.4.4. 本地退出

User-initiated logout 将从 OIDC 供应商注销用户。如果将其用作单点登录,这可能不是您需要的。例如,如果您的 OIDC 供应商是 Google,您将从 Google 及其服务中登出。相反,用户可能只希望退出该特定应用程序。另一个用例可能是 OIDC 供应商没有注销端点。

通过使用 OidcSession,您可以支持本地注销,这意味着只清除本地会话 cookie,如下例所示:

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

import io.quarkus.oidc.OidcSession;

@Path("/service")
public class ServiceResource {

    @Inject
    OidcSession oidcSession;

    @GET
    @Path("logout")
    public String logout() {
        oidcSession.logout().await().indefinitely();
        return "You are logged out".
    }
Copy to Clipboard Toggle word wrap
3.2.4.4.4.1. 使用 OidcSession 进行本地注销

io.quarkus.oidc.OidcSession 是当前 IdToken 的打包程序,可帮助执行 本地注销,检索当前会话的租户标识符,并检查会话何时过期。随着时间的推移,将向它添加更有用的方法。

3.2.4.5. 会话管理

默认情况下,注销基于 OIDC 供应商发布的 ID 令牌的过期时间。当 ID 令牌过期时,Quarkus 端点中的当前用户会话无效,用户会被重新重定向到 OIDC 供应商以进行身份验证。如果 OIDC 供应商中的会话仍然处于活跃状态,则用户会自动重新验证,而无需再次提供其凭证。

通过启用 quarkus.oidc.token.refresh-expired 属性,可以自动扩展当前用户会话。如果设置为 true,当当前 ID 令牌过期时,将使用刷新令牌授权来刷新 ID 令牌,以及访问和刷新令牌。

提示

如果您有一个 用于服务应用程序的单个页面应用程序,您的 OIDC 供应商脚本(如 keycloak.js )正在管理授权代码流,则该脚本也会控制 SPA 身份验证会话生命周期。

如果您使用 Quarkus OIDC web-app 应用程序,则 Quarkus OIDC 代码身份验证机制管理用户会话生命周期。

要使用刷新令牌,您应该仔细配置会话 Cookie 年龄。会话年龄应超过 ID 令牌寿命,并且接近或等于刷新令牌生命周期。

您可以通过添加当前 ID 令牌的 lifespan 值以及 quarkus.oidc. authentication.session-age-extension 和 quarkus.oidc.token.lifespan-grace 属性的值来计算会话年龄。

提示

如果需要,只使用 quarkus.oidc.authentication.session-age-extension 属性来显著扩展会话生命周期。您可以使用 quarkus.oidc.token.lifespan-grace 属性来考虑一些小时钟偏移。

当当前经过身份验证的用户返回到受保护的 Quarkus 端点并且与会话 Cookie 关联的 ID 令牌已过期时,默认情况下,用户会自动重定向到 OIDC Authorization 端点来重新验证。如果用户和此 OIDC 供应商间的会话仍然活跃,OIDC 供应商可能会再次挑战用户,如果会话配置为最后的时间超过 ID 令牌,则可能会出现这种情况。

如果 quarkus.oidc.token.refresh-expired 设为 true,则使用返回初始授权代码的刷新令牌刷新过期的 ID 令牌(和访问令牌)。此刷新令牌也可能被回收(刷新)本身作为此过程的一部分。因此,会创建新的会话 Cookie,会话会被扩展。

注意

在用户未激活的情况下,您可以使用 quarkus.oidc.authentication.session-age-extension 属性来帮助处理过期的 ID 令牌。如果 ID 令牌过期,则会话 Cookie 可能不会在下一个用户请求期间返回到 Quarkus 端点,因为 Cookie 生命周期已过。Quarkus 假设此请求是第一个身份验证请求。将 quarkus.oidc.authentication.session-age-extension 设置为您的裸机用户,并根据您的安全策略。

您可以进一步进入一个步骤,并主动刷新 ID 令牌或访问令牌过期。将 quarkus.oidc.token.refresh-token-time-skew 设置为您要预计刷新的值。如果在当前用户请求过程中,计算当前 ID 令牌将在此 quarkus.oidc.token.refresh-token-time-skew 中过期,然后被刷新,并创建新的会话 cookie。此属性应设置为小于 ID 令牌生命周期的值;更接近这个生命周期值,ID 令牌会被刷新的频率。

您可以通过具有简单的 JavaScript 功能定期 ping Quarkus 端点来进一步优化这个过程,以模拟用户活动,从而减少用户必须重新验证的时间框架。

注意

您无法无限期扩展用户会话。当刷新令牌已过期后,在 OIDC 供应商端点中的返回用户必须在 OIDC 供应商端点中重新进行身份验证。

3.2.5. 与 GitHub 和非OIDC OAuth2 供应商集成

GitHub 或 LinkedIn 等一些已知的供应商不是 OpenID Connect 供应商,但支持 授权代码流的 OAuth2 供应商。例如,GitHub OAuth2LinkedIn OAuth2。请记住,OIDC 基于 OAuth2 构建。

OIDC 和 OAuth2 供应商的主要区别在于,除了标准授权代码流 访问和 刷新 OAuth2 供应商返回的令牌外,OIDC 供应商还会返回一个代表用户身份验证的 ID 令牌。

GitHub 等 OAuth2 提供程序不返回 IdToken,用户身份验证是隐式的,间接由 访问令牌 表示。此 访问令牌 代表了一个经过身份验证的用户,授权当前的 Quarkus web-app 应用代表经过身份验证的用户访问某些数据。

对于 OIDC,您可以将 ID 令牌验证为身份验证的有效性,而在 OAuth2 时验证访问令牌。这随后通过调用需要访问令牌的端点,并且通常会返回用户信息来完成。这个方法与 OIDC UserInfo 方法类似,代表 Quarkus OIDC 获取的 UserInfo

例如,在使用 GitHub 时,Quarkus 端点可以 获取访问令牌,它允许 Quarkus 端点为当前用户请求 GitHub 配置集。

要支持与这样的 OAuth2 服务器的集成,quarkus-oidc 需要以不同的方式配置,以允许在没有 IdToken:quarkus.oidc.authentication.id-token-required=false 的情况下配置授权代码流响应。

注意

虽然您要将扩展配置为支持没有 IdToken 的授权代码流,但会生成内部 IdToken 来标准化 quarkus-oidc 操作的方式。您可以使用 IdToken 支持身份验证会话,并避免在每个请求上将用户重定向到供应商,如 GitHub。在这种情况下,会话寿命被设置为 5 分钟,您可以进一步进行扩展,如 会话管理 部分中所述。

这简化了如何处理支持多个 OIDC 供应商的应用程序。

下一步是确保返回的访问令牌很有用,并且对当前 Quarkus 端点有效。第一种方法是,如果提供商提供了这样的端点,则通过配置 quarkus.oidc.introspection-path 来调用 OAuth2 提供程序内省端点。在这种情况下,您可以使用 quarkus.oidc.roles.source=accesstoken 将访问令牌用作角色源。如果没有内省端点,您可以尝试从提供程序请求 UserInfo,因为它至少将验证访问令牌。为此,请指定 quarkus.oidc.token.verify-access-token-with-user-info=true。您还需要将 quarkus.oidc.user-info-path 属性设置为 URL 端点,该端点获取用户信息(或访问令牌保护的端点)。对于 GitHub,因为它没有内省端点,需要请求 UserInfo。

注意

需要 UserInfo 涉及在每个请求上进行远程调用。因此,您可能需要考虑缓存 UserInfo 数据。如需更多信息,请参阅"OpenID Connect (OIDC) Bearer 令牌身份验证"指南中的 Token Introspection 和 UserInfo 缓存 部分。

或者,您可能希望请求将 UserInfo 嵌入到内部生成的 IdToken 中,并带有 quarkus.oidc.cache-user-info-in-idtoken=true 属性。这种方法的优点是,默认情况下,不会保留缓存的用户 Info 状态与端点 - 相反,它将存储在会话 Cookie 中。如果 UserInfo 包含敏感数据,您可能还需要考虑加密 IdToken。如需更多信息,请参阅使用 TokenStateManager 加密令牌

OAuth2 服务器可能不支持已知的配置端点。在这种情况下,您必须禁用发现并配置授权、令牌和内省和 UserInfo 端点路径。

对于知名的 OIDC 或 OAuth2 供应商,如 Apple、Facebook、GitHub、Google、Microsoft、Spotify 和 Artistic,Quarkus 可使用 quarkus.oidc.provider 属性简化应用程序的配置。以下是您可以在创建 GitHub OAuth 应用程序后将 quarkus-oidc 与 GitHub 集成。配置 Quarkus 端点,如下所示:

quarkus.oidc.provider=github
quarkus.oidc.client-id=github_app_clientid
quarkus.oidc.credentials.secret=github_app_clientsecret

# user:email scope is requested by default, use 'quarkus.oidc.authentication.scopes' to request different scopes such as `read:user`.
# See https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps for more information.

# Consider enabling UserInfo Cache
# quarkus.oidc.token-cache.max-size=1000
# quarkus.oidc.token-cache.time-to-live=5M
#
# Or having UserInfo cached inside IdToken itself
# quarkus.oidc.cache-user-info-in-idtoken=true
Copy to Clipboard Toggle word wrap

有关配置其他已知的供应商的更多信息,请参阅 OpenID Connect 供应商

这是端点所需要的,如这个端点使用 GET http://localhost:8080/github/userinfo 返回当前验证的用户配置集,并将其作为单独的 UserInfo 属性访问:

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

import io.quarkus.oidc.UserInfo;
import io.quarkus.security.Authenticated;

@Path("/github")
@Authenticated
public class TokenResource {

    @Inject
    UserInfo userInfo;

    @GET
    @Path("/userinfo")
    @Produces("application/json")
    public String getUserInfo() {
        return userInfo.getUserInfoString();
    }
}
Copy to Clipboard Toggle word wrap

如果您支持多个社交供应商,它带有 OpenID Connect Multi-Tenancy 的帮助,例如 Google,它是一个 OIDC 供应商,返回 IdToken 和 GitHub,它是一个 OAuth2 供应商,它没有返回 IdToken,只允许访问 UserInfo,然后您可以让端点与 Google 和 GitHub 流注入的 SecurityIdentity 工作。当 GitHub 流处于活跃状态时,需要一个简单的 SecurityIdentity,其中使用内部生成的 IdToken 创建的主体将替换为基于 UserInfo的主体:

package io.quarkus.it.keycloak;

import java.security.Principal;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.oidc.UserInfo;
import io.quarkus.security.identity.AuthenticationRequestContext;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.identity.SecurityIdentityAugmentor;
import io.quarkus.security.runtime.QuarkusSecurityIdentity;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomSecurityIdentityAugmentor implements SecurityIdentityAugmentor {

    @Override
    public Uni<SecurityIdentity> augment(SecurityIdentity identity, AuthenticationRequestContext context) {
        RoutingContext routingContext = identity.getAttribute(RoutingContext.class.getName());
        if (routingContext != null && routingContext.normalizedPath().endsWith("/github")) {
	        QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(identity);
	        UserInfo userInfo = identity.getAttribute("userinfo");
	        builder.setPrincipal(new Principal() {

	            @Override
	            public String getName() {
	                return userInfo.getString("preferred_username");
	            }

	        });
	        identity = builder.build();
        }
        return Uni.createFrom().item(identity);
    }

}
Copy to Clipboard Toggle word wrap

现在,当用户使用 Google 或 GitHub 登录应用程序时,以下代码将可以正常工作:

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

import io.quarkus.security.Authenticated;
import io.quarkus.security.identity.SecurityIdentity;

@Path("/service")
@Authenticated
public class TokenResource {

    @Inject
    SecurityIdentity identity;

    @GET
    @Path("/google")
    @Produces("application/json")
    public String getUserName() {
        return identity.getPrincipal().getName();
    }

    @GET
    @Path("/github")
    @Produces("application/json")
    public String getUserName() {
        return identity.getPrincipal().getUserName();
    }
}
Copy to Clipboard Toggle word wrap

可能更为简单的替代方案是注入 @IdToken JsonWebTokenUserInfo,并在处理返回 IdToken 的提供程序时使用 JsonWebToken,并将 UserInfo 与不返回 IdToken 的提供程序一起使用。

您必须确保您在 GitHub OAuth 应用程序配置中输入的回调路径与希望在 GitHub 身份验证和应用程序授权成功后重定向用户的端点路径匹配。在这种情况下,它必须设置为 http:localhost:8080/github/userinfo

3.2.6. 侦听重要的身份验证事件

您可以注册 @ApplicationScoped bean,它将观察重要的 OIDC 身份验证事件。当用户第一次登录时,重新验证或刷新会话时,会更新监听程序。未来可能会报告更多事件。例如:

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;

import io.quarkus.oidc.IdTokenCredential;
import io.quarkus.oidc.SecurityEvent;
import io.quarkus.security.identity.AuthenticationRequestContext;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class SecurityEventListener {

    public void event(@Observes SecurityEvent event) {
        String tenantId = event.getSecurityIdentity().getAttribute("tenant-id");
        RoutingContext vertxContext = event.getSecurityIdentity().getAttribute(RoutingContext.class.getName());
        vertxContext.put("listener-message", String.format("event:%s,tenantId:%s", event.getEventType().name(), tenantId));
    }
}
Copy to Clipboard Toggle word wrap
提示

您可以侦听其他安全事件,如 Security Tips and Tricks 指南中的 Observe security events 部分所述。

3.2.7. 将令牌传播到下游服务

有关授权代码流访问令牌传播到下游服务的详情,请参考 Token Propagation 部分。

3.3. 集成注意事项

您的应用程序由 OIDC 集成在一个环境中,可以从单页应用程序调用。它必须与已知的 OIDC 供应商一起工作,在 HTTP Reverse Proxy 后面运行,需要外部和内部访问,等等。

本节讨论这些注意事项。

3.3.1. 单页应用程序

您可以检查在"OpenID Connect (OIDC) Bearer 令牌身份验证"指南的 单页应用程序 部分中建议采用单页应用程序(SPAs)是否满足您的要求。

如果您希望使用带有 Quarkus Web 应用程序的 SPAs 和 JavaScript API,如 FetchXMLHttpRequest(XHR),请注意 OIDC 供应商可能不支持跨原始资源共享(CORS)进行授权端点,其中用户会在来自 Quarkus 的重定向后进行身份验证。如果 Quarkus 应用程序和 OIDC 供应商托管在不同的 HTTP 域、端口或两者上,则会导致身份验证失败。

在这种情况下,将 quarkus.oidc.authentication.java-script-auto-redirect 属性设置为 false,这将指示 Quarkus 返回 499 状态代码和带有 OIDC 值的 WWW-Authenticate 标头。

浏览器脚本必须设置标头,将当前请求标识为当 quarkus.oidc.authentication.java-script-auto-redirect 属性设置为 false 时返回的 499 状态代码的 JavaScript 请求。

如果脚本引擎设置特定于引擎的请求标头本身,您可以注册自定义 quarkus.oidc.JavaScriptRequestChecker bean,它将告知 Quarkus 如果当前请求是 JavaScript 请求。例如,如果 JavaScript 引擎设置标头,如 HX-Request: true,则可以进行检查,如下所示:

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.oidc.JavaScriptRequestChecker;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomJavaScriptRequestChecker implements JavaScriptRequestChecker {

    @Override
    public boolean isJavaScriptRequest(RoutingContext context) {
        return "true".equals(context.request().getHeader("HX-Request"));
    }
}
Copy to Clipboard Toggle word wrap

499 状态代码中,重新加载最后请求页面。

否则,还必须更新浏览器脚本,以使用 JavaScript 值设置 X-Requested-With 标头,并在 499 状态代码时重新加载最后一个请求页面。

例如:

Future<void> callQuarkusService() async {
    Map<String, String> headers = Map.fromEntries([MapEntry("X-Requested-With", "JavaScript")]);

    await http
        .get("https://localhost:443/serviceCall")
        .then((response) {
            if (response.statusCode == 499) {
                window.location.assign("https://localhost.com:443/serviceCall");
            }
         });
  }
Copy to Clipboard Toggle word wrap

3.3.2. 跨原始资源共享

如果您计划从在不同域上运行的单页应用消耗此应用,则需要配置跨原始资源共享(CORS)。如需更多信息,请参阅"Cross-origin 资源共享"指南中的 CORS 过滤器 部分。

3.3.3. 在反向代理后面运行 Quarkus 应用程序

如果您的 Quarkus 应用程序在反向代理、网关或防火墙后面运行,则 OIDC 身份验证机制可能会受到影响,当 HTTP 主机标头 可能会重置为内部 IP 地址,HTTPS 连接可能会被终止,以此类推。例如,授权代码流 redirect_uri 参数可能会设置为内部主机,而不是预期的外部。

在这种情况下,需要将 Quarkus 配置为识别代理转发的原始标头。如需更多信息,请参阅 反向代理 Vert.x 文档部分的运行

例如,如果您的 Quarkus 端点在 Kubernetes Ingress 后面的集群中运行,则从 OIDC 供应商重新指向此端点的重定向可能无法正常工作,因为计算的 redirect_uri 参数可能指向内部端点地址。您可以使用以下配置来解决这个问题,其中 Kubernetes Ingress 设置 X-ORIGINAL-HOST 来代表外部端点地址:

quarkus.http.proxy.proxy-address-forwarding=true
quarkus.http.proxy.allow-forwarded=false
quarkus.http.proxy.enable-forwarded-host=true
quarkus.http.proxy.forwarded-host-header=X-ORIGINAL-HOST
Copy to Clipboard Toggle word wrap

当 Quarkus 应用程序在 SSL 终止反向代理后面运行时,也可以使用 quarkus.oidc.authentication.force-redirect-https-scheme 属性。

3.3.4. 对 OIDC 供应商的外部和内部访问

与 URL 自动发现或配置相对于 quarkus.oidc.auth-server-url 内部 URL 相比,OIDC 供应商外部可访问的授权、注销和其他端点可以有不同的 HTTP (S) URL。在这种情况下,端点可能会报告签发者验证失败,并重定向到外部访问的 OIDC 供应商端点可能会失败。

如果您使用 Keycloak,那么使用 KEYCLOAK_FRONTEND_URL 系统属性将其启动,设置为外部可访问的基本 URL。如果使用其他 OIDC 供应商,请查看您的供应商文档。

3.4. OIDC SAML 身份代理

如果您的身份提供程序没有实现 OpenID Connect,而只有旧的基于 XML 的 SAML2.0 SSO 协议,则无法将 Quarkus 用作 SAML 2.0 适配器,类似于 quarkus-oidc 如何用作 OIDC 适配器。

但是,许多 OIDC 供应商,如 Keycloak、Okta、Auth0 和 Microsoft ADFS 为 SAML 2.0 网桥提供 OIDC。您可以在 OIDC 供应商中创建到 SAML 2.0 供应商的身份代理连接,并使用 quarkus-oidc 验证您的用户到此 SAML 2.0 供应商,并具有 OIDC 供应商协调 OIDC 和 SAML 2.0 通信。至于 Quarkus 端点,他们可以继续使用相同的 Quarkus Security、OIDC API、注释,如 @AuthenticatedSecurityIdentity 等。

例如,假设 Okta 是您的 SAML 2.0 供应商,Keycloak 是您的 OIDC 供应商。以下是如何使用 Okta SAML 2.0 供应商将 Keycloak 配置为代理的典型序列。

首先,在 Okta Dashboard/Applications 中创建一个新的 SAML2 集成:

例如,将其命名为 OktaSaml

接下来,将其配置为指向 Keycloak SAML 代理端点。此时,您需要知道 Keycloak 域的名称,如 quarkus,并假定 Keycloak SAML 代理别名为 saml,输入端点地址 http:localhost:8081/realms/quarkus/broker/saml/endpoint。输入服务供应商(SP)实体 ID 作为 http:localhost:8081/realms/quarkus,其中 http://localhost:8081 是 Keycloak 基础地址,saml 是代理别名:

接下来,保存此 SAML 集成并记录其元数据 URL:

接下来,在 Keycloak 中添加 SAML 供应商:

首先,照常创建新域或将现有域导入到 Keycloak。在这种情况下,域名必须是 quarkus

现在,在 quarkus 域属性中,导航到 Identity Providers 并添加新的 SAML 供应商:

请注意,别名被设为 samlRedirect URIhttp:localhost:8081/realms/quarkus/broker/saml/endpoint服务供应商实体 IDhttp:localhost:8081/realms/quarkus - 与您在上一步中创建 Okta SAML 集成时输入的值相同。

最后,设置 Service entity descriptor 以指向上一步末尾的 Okta SAML 集成元数据 URL。

接下来,您可以导航到 Authentication/browser/Identity Provider Redirector config,将 Alias 和 Default Identity Provider 属性注册为默认提供程序,并将 AliasDefault Identity Provider 属性设为 saml。如果您没有将其配置为默认供应商,在身份验证时提供 2 个选项:

  • 使用 SAML 供应商进行身份验证
  • 直接使用名称和密码向 Keycloak 进行身份验证

现在,将 Quarkus OIDC web-app 应用程序配置为指向 Keycloak quarkus realm quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus。然后,您已准备好使用 OIDC 到 SAML 网桥(由 Keycloak OIDC 和 Okta SAML 2.0 供应商)向 Okta SAML 2.0 供应商验证 Quarkus 用户。

您可以配置其他 OIDC 供应商,以提供与为 Keycloak 执行的方式相似的 SAML 网桥。

3.5. 测试

当测试涉及向独立的 OIDC 服务器进行身份验证时,测试通常很复杂。Quarkus 提供多个选项,从模拟到 OIDC 供应商的本地运行。

首先,将以下依赖项添加到 test 项目中:

  • 使用 Maven:

    <dependency>
        <groupId>net.sourceforge.htmlunit</groupId>
        <artifactId>htmlunit</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>*</artifactId>
           </exclusion>
        </exclusions>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-junit5</artifactId>
        <scope>test</scope>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    testImplementation("net.sourceforge.htmlunit:htmlunit")
    testImplementation("io.quarkus:quarkus-junit5")
    Copy to Clipboard Toggle word wrap

3.5.1. Wiremock

添加以下依赖项:

  • 使用 Maven:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-test-oidc-server</artifactId>
        <scope>test</scope>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    testImplementation("io.quarkus:quarkus-test-oidc-server")
    Copy to Clipboard Toggle word wrap

准备 REST 测试端点并设置 application.properties。例如:

# keycloak.url is set by OidcWiremockTestResource
quarkus.oidc.auth-server-url=${keycloak.url}/realms/quarkus/
quarkus.oidc.client-id=quarkus-web-app
quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app
Copy to Clipboard Toggle word wrap

最后,编写测试代码,例如:

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

import com.gargoylesoftware.htmlunit.SilentCssErrorHandler;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.oidc.server.OidcWiremockTestResource;

@QuarkusTest
@QuarkusTestResource(OidcWiremockTestResource.class)
public class CodeFlowAuthorizationTest {

    @Test
    public void testCodeFlow() throws Exception {
        try (final WebClient webClient = createWebClient()) {
            // the test REST endpoint listens on '/code-flow'
            HtmlPage page = webClient.getPage("http://localhost:8081/code-flow");

            HtmlForm form = page.getFormByName("form");
            // user 'alice' has the 'user' role
            form.getInputByName("username").type("alice");
            form.getInputByName("password").type("alice");

            page = form.getInputByValue("login").click();

            assertEquals("alice", page.getBody().asText());
        }
    }

    private WebClient createWebClient() {
        WebClient webClient = new WebClient();
        webClient.setCssErrorHandler(new SilentCssErrorHandler());
        return webClient;
    }
}
Copy to Clipboard Toggle word wrap

OidcWiremockTestResource 可识别 aliceadmin 用户。用户 alice 默认具有用户角色 - 它可以通过 quarkus.test.oidc.token. user -roles 系统属性进行自定义。用户 admin 默认具有 用户和 admin 角色 - 它可以通过 quarkus.test.oidc.token.admin-roles 系统属性进行自定义。

另外,OidcWiremockTestResource 将令牌签发者和 audience 设置为 https://service.example.com,它可以通过 quarkus.test.oidc.token.issuerquarkus.test.oidc.token.audience 系统属性进行自定义。

OidcWiremockTestResource 可用于模拟所有 OIDC 供应商。

3.5.2. Keycloak 的 dev Services

建议对 Keycloak 使用 Dev Services 进行 集成测试。用于 Keycloak 的 dev Services 将启动并初始化测试容器:它将创建一个 quarkus 域、quarkus-app 客户端(secret secret),并添加 alice (admin user roles)和 bob (用户角色)用户,您可以在其中自定义所有这些属性。

首先,准备 application.properties。您可以从完全空的 application.properties 文件作为 Keycloak 的 Dev Services 开始,注册指向正在运行的测试容器的 quarkus.oidc.auth-server-url,以及 quarkus.oidc.client-id=quarkus-appquarkus.oidc.credentials.secret=secret

但是,如果您已经配置了所有必需的 quarkus-oidc 属性,则您只需要将 quarkus.oidc.auth-server-urlKeycloak 的 Dev Services 的 prod 配置集关联,才能启动容器。例如:

%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
Copy to Clipboard Toggle word wrap

如果在运行测试前必须将自定义域文件导入到 Keycloak 中,您可以为 Keycloak 配置 Dev Services,如下所示:

%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.keycloak.devservices.realm-path=quarkus-realm.json
Copy to Clipboard Toggle word wrap

最后,按照与 Wiremock 部分相同的方式编写测试代码。唯一的区别是 @QuarkusTestResource 不再需要:

@QuarkusTest
public class CodeFlowAuthorizationTest {
}
Copy to Clipboard Toggle word wrap

3.5.3. TestSecurity 注解

您可以使用 @TestSecurity 和 @OidcSecurity 注释来测试 web-app 应用端点代码,这取决于以下注入之一,或者全部四个:

  • ID JsonWebToken
  • Access JsonWebToken
  • UserInfo
  • OidcConfigurationMetadata

有关更多信息,请参阅将 TestingSecurity 与注入的 JsonWebToken 搭配使用

3.5.4. 检查日志中的错误

要查看有关令牌验证错误的详情,您必须启用 io.quarkus.oidc.runtime.OidcProvider TRACE 级别日志记录:

quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.OidcProvider".min-level=TRACE
Copy to Clipboard Toggle word wrap

要查看有关 OidcProvider 客户端初始化错误的详细信息,请启用 io.quarkus.oidc.runtime.OidcRecorder TRACE 级别日志记录:

quarkus.log.category."io.quarkus.oidc.runtime.OidcRecorder".level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.OidcRecorder".min-level=TRACE
Copy to Clipboard Toggle word wrap

quarkus dev 控制台,键入 j 以更改应用全局日志级别。

3.6. 参考

探索如何使用 Quarkus OpenID Connect (OIDC)授权代码流机制以及 Quarkus OIDC 扩展来保护应用程序 HTTP 端点,从而提供强大的身份验证和授权。

如需更多信息,请参阅 用于保护 Web 应用程序的 OIDC 代码流机制

要了解知名的社交提供商(如 Apple、Facebook、GitHub、Google、Maasy、Microsoft、Twitch、Twitch、Twitch、Twitch 和 Spotify 如何与 Quarkus OIDC 一起使用,请参阅配置已知的 OpenID Connect 供应商。请参阅 Quarkus 中的验证机制

如果要使用 OIDC Bearer 令牌身份验证来保护服务应用程序,请参阅 OIDC Bearer 令牌身份验证

4.1. 先决条件

要完成本指南,您需要:

4.2. 架构

在这个示例中,我们使用单个页面构建一个简单的 Web 应用程序:

  • /index.html

此页面受到保护,只有经过身份验证的用户才能访问它。

4.3. 解决方案

按照下一小节中的说明,并逐步创建应用程序步骤。或者,您可以右到已完成的示例。

运行 git clone https://github.com/quarkusio/quarkus-quickstarts.git -b 3.8 命令克隆 Git 存储库。或者,下载 存档

解决方案位于 security-openid-connect-web-authentication-quickstart 目录中

4.4. 创建 Maven 项目

首先,我们需要新的项目。运行以下命令创建新项目:

  • 使用 Quarkus CLI:

    quarkus create app org.acme:security-openid-connect-web-authentication-quickstart \
        --extension='resteasy-reactive,oidc' \
        --no-code
    cd security-openid-connect-web-authentication-quickstart
    Copy to Clipboard Toggle word wrap

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

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

  • 使用 Maven:

    mvn io.quarkus.platform:quarkus-maven-plugin:3.8.5:create \
        -DprojectGroupId=org.acme \
        -DprojectArtifactId=security-openid-connect-web-authentication-quickstart \
        -Dextensions='resteasy-reactive,oidc' \
        -DnoCode
    cd security-openid-connect-web-authentication-quickstart
    Copy to Clipboard Toggle word wrap

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

对于 Windows 用户:

  • 如果使用 cmd,(不要使用反向斜杠 \ 并将所有内容放在同一行中)
  • 如果使用 Powershell,则双引号中的 wrap -D 参数,如 "-DprojectArtifactId=security-openid-connect-web-authentication-quickstart"

如果您已经配置了 Quarkus 项目,您可以通过在项目基本目录中运行以下命令来将 oidc 扩展添加到项目中:

  • 使用 Quarkus CLI:

    quarkus extension add oidc
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw quarkus:add-extension -Dextensions='oidc'
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew addExtension --extensions='oidc'
    Copy to Clipboard Toggle word wrap

这会在您的构建文件中添加以下依赖项:

  • 使用 Maven:

    <dependency>
       <groupId>io.quarkus</groupId>
       <artifactId>quarkus-oidc</artifactId>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    implementation("io.quarkus:quarkus-oidc")
    Copy to Clipboard Toggle word wrap

4.5. 编写应用程序

我们编写一个简单的 Jakarta REST 资源,该资源在授权代码授予响应中返回的所有令牌:

package org.acme.security.openid.connect.web.authentication;

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

import org.eclipse.microprofile.jwt.Claims;
import org.eclipse.microprofile.jwt.JsonWebToken;

import io.quarkus.oidc.IdToken;
import io.quarkus.oidc.RefreshToken;

@Path("/tokens")
public class TokenResource {

   /**
    * Injection point for the ID token issued by the OpenID Connect provider
    */
   @Inject
   @IdToken
   JsonWebToken idToken;

   /**
    * Injection point for the access token issued by the OpenID Connect provider
    */
   @Inject
   JsonWebToken accessToken;

   /**
    * Injection point for the refresh token issued by the OpenID Connect provider
    */
   @Inject
   RefreshToken refreshToken;

   /**
    * Returns the tokens available to the application.
    * This endpoint exists only for demonstration purposes.
    * Do not expose these tokens in a real application.
    *
    * @return an HTML page containing the tokens available to the application.
    */
   @GET
   @Produces("text/html")
   public String getTokens() {
       StringBuilder response = new StringBuilder().append("<html>")
               .append("<body>")
               .append("<ul>");


       Object userName = this.idToken.getClaim(Claims.preferred_username);

       if (userName != null) {
           response.append("<li>username: ").append(userName.toString()).append("</li>");
       }

       Object scopes = this.accessToken.getClaim("scope");

       if (scopes != null) {
           response.append("<li>scopes: ").append(scopes.toString()).append("</li>");
       }

       response.append("<li>refresh_token: ").append(refreshToken.getToken() != null).append("</li>");

       return response.append("</ul>").append("</body>").append("</html>").toString();
   }
}
Copy to Clipboard Toggle word wrap

此端点注入了 ID、访问和刷新令牌。它从 ID 令牌、访问令牌中的 范围 声明和刷新令牌可用性状态返回 preferred_username 声明。

只有在端点需要使用 ID 令牌与当前经过身份验证的用户交互时,您只需要注入令牌,或使用访问令牌代表此用户访问下游服务。

如需更多信息,请参阅参考指南中的 访问 ID 和访问令牌 部分。

4.6. 配置应用程序

OIDC 扩展允许您使用 src/main/resources 目录中的 application.properties 文件来定义配置。

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=frontend
quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
Copy to Clipboard Toggle word wrap

这是在为应用程序启用身份验证时可以拥有的最简单配置。

quarkus.oidc.client-id 属性引用 OIDC 供应商发布的 client_idquarkus.oidc.credentials.secret 属性设置客户端 secret。

quarkus.oidc.application-type 属性被设置为 web-app 告知 Quarkus 您要启用 OIDC 授权代码流,以便您的用户重定向到 OIDC 供应商进行验证。

最后,quarkus.http.auth.permission.authenticated 权限被设置为告诉 Quarkus 您要保护的路径。在这种情况下,所有路径都由策略保护,以确保只有 经过身份验证的用户 可以访问它们。有关更多信息,请参阅 安全授权指南

4.7. 启动并启用 Keycloak 服务器

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

docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev
Copy to Clipboard Toggle word wrap

其中 keycloak.version 设置为 24.0.0 或更高版本。

您可以在 localhost:8180 访问您的 Keycloak 服务器。

要访问 Keycloak 管理控制台,请以 admin 用户身份登录。用户名和密码都是 admin

要创建新域,请导入 realm 配置文件。如需更多信息,请参阅关于如何 创建和配置新域的 Keycloak 文档

4.8. 在 dev 和 JVM 模式下运行应用程序

要在 dev 模式下运行应用程序,请使用:

  • 使用 Quarkus CLI:

    quarkus dev
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw quarkus:dev
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew --console=plain quarkusDev
    Copy to Clipboard Toggle word wrap

在以 dev 模式探索应用后,您可以将其作为标准 Java 应用运行。

首先,编译它:

  • 使用 Quarkus CLI:

    quarkus build
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw install
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew build
    Copy to Clipboard Toggle word wrap

然后运行它:

java -jar target/quarkus-app/quarkus-run.jar
Copy to Clipboard Toggle word wrap

4.9. 以原生模式运行应用程序

相同的演示可编译到原生代码中。不需要修改。

这意味着,您不再需要在生产环境中安装 JVM,因为运行时技术包含在生成的二进制中,并优化以最小资源运行。

编译需要更长的时间,因此默认关闭此步骤。您可以通过启用原生构建来再次构建:

  • 使用 Quarkus CLI:

    quarkus build --native
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw install -Dnative
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew build -Dquarkus.package.type=native
    Copy to Clipboard Toggle word wrap

在一段时间后,您可以直接运行这个二进制文件:

./target/security-openid-connect-web-authentication-quickstart-runner
Copy to Clipboard Toggle word wrap

4.10. 测试应用

要测试应用程序,请打开浏览器并访问以下 URL:

如果所有内容都按预期工作,您会被重定向到 Keycloak 服务器以进行身份验证。

要向应用程序进行身份验证,请在 Keycloak 登录页面中输入以下凭证:

  • 用户名: alice
  • 密码 : alice

Login 按钮后,您将重新重定向到应用程序,并创建一个会话 Cookie。

此演示的会话在短时间内有效,每次页面刷新时,将要求您重新验证。有关如何增加会话超时的详情,请参考 Keycloak 会话超时 文档。例如,如果您在 dev 模式下使用 Dev Services for Keycloak Admin 链接,您可以从 dev UI 直接访问 Keycloak Admin 控制台:

有关编写依赖于 Keycloak 的 Dev Services 的集成测试的更多信息,请参阅 Keycloak 的 Dev Services 部分。

4.11. 概述

您已了解如何设置和使用 OIDC 授权代码流机制来保护和测试应用程序 HTTP 端点。完成本教程后,探索 OIDC Bearer 令牌身份验证 和其他身份验证机制

4.12. 参考

第 5 章 使用 OpenID Connect (OIDC)多租户

本指南演示了您的 OpenID Connect (OIDC)应用程序如何支持多租户,以从单个应用程序提供多个租户。这些租户可以是同一 OIDC 供应商中的不同域或安全域,甚至不同的 OIDC 供应商。

在为来自同一应用程序的多个客户(如在 SaaS 环境中)提供服务时,每个客户都可以作为不同的租户。通过启用对应用程序的多租户支持,您可以支持每个租户的不同身份验证策略,甚至针对不同的 OIDC 供应商(如 Keycloak 和 Google)进行身份验证。

要使用 Bearer Token Authorization 授权租户,请参阅 OpenID Connect (OIDC) Bearer 令牌身份验证 指南。

要使用 OIDC 授权代码流验证和授权租户,请阅读 用于保护 Web 应用程序指南的 OpenID Connect 授权代码流机制

另外,请参阅 OpenID Connect (OIDC)配置属性 参考指南。

5.1. 先决条件

要完成本指南,您需要:

5.2. 架构

在这个示例中,我们构建一个支持两种资源方法的简单应用程序:

  • /{tenant}

此资源返回从 OIDC 供应商发布的有关经过身份验证的用户和当前租户发布的 ID 令牌获取的信息。

  • /{tenant}/bearer

此资源返回从 OIDC 供应商发布的有关经过身份验证的用户和当前租户发布的访问令牌获取的信息。

5.3. 解决方案

为了充分理解,我们建议您按照接下来的逐步说明来构建应用程序。

或者,如果您想从已完成的示例开始,克隆 Git 存储库: git clone https://github.com/quarkusio/quarkus-quickstarts.git -b 3.8 或下载 归档

该解决方案位于 security-openid-connect-multi-tenancy-quickstart 目录中

5.4. 创建 Maven 项目

首先,我们需要新的项目。使用以下命令创建新项目:

  • 使用 Quarkus CLI:

    quarkus create app org.acme:security-openid-connect-multi-tenancy-quickstart \
        --extension='oidc,resteasy-reactive-jackson' \
        --no-code
    cd security-openid-connect-multi-tenancy-quickstart
    Copy to Clipboard Toggle word wrap

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

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

  • 使用 Maven:

    mvn io.quarkus.platform:quarkus-maven-plugin:3.8.5:create \
        -DprojectGroupId=org.acme \
        -DprojectArtifactId=security-openid-connect-multi-tenancy-quickstart \
        -Dextensions='oidc,resteasy-reactive-jackson' \
        -DnoCode
    cd security-openid-connect-multi-tenancy-quickstart
    Copy to Clipboard Toggle word wrap

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

对于 Windows 用户:

  • 如果使用 cmd,(不要使用反向斜杠 \ 并将所有内容放在同一行中)
  • 如果使用 Powershell,则双引号中的 wrap -D 参数,如 "-DprojectArtifactId=security-openid-connect-multi-tenancy-quickstart"

如果您已经配置了 Quarkus 项目,请在项目基本目录中运行以下命令来将 oidc 扩展添加到项目中:

  • 使用 Quarkus CLI:

    quarkus extension add oidc
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw quarkus:add-extension -Dextensions='oidc'
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew addExtension --extensions='oidc'
    Copy to Clipboard Toggle word wrap

这会在构建文件中添加以下内容:

  • 使用 Maven:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-oidc</artifactId>
    </dependency>
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    implementation("io.quarkus:quarkus-oidc")
    Copy to Clipboard Toggle word wrap

5.5. 编写应用程序

首先实施 /{tenant} 端点。正如您在以下源代码中看到的那样,它只是常规 Jakarta REST 资源:

package org.acme.quickstart.oidc;

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

import org.eclipse.microprofile.jwt.JsonWebToken;

import io.quarkus.oidc.IdToken;

@Path("/{tenant}")
public class HomeResource {
    /**
     * Injection point for the ID Token issued by the OIDC provider.
     */
    @Inject
    @IdToken
    JsonWebToken idToken;

    /**
     * Injection point for the Access Token issued by the OIDC provider.
     */
    @Inject
    JsonWebToken accessToken;

    /**
     * Returns the ID Token info.
     * This endpoint exists only for demonstration purposes.
     * Do not expose this token in a real application.
     *
     * @return ID Token info
     */
    @GET
    @Produces("text/html")
    public String getIdTokenInfo() {
        StringBuilder response = new StringBuilder().append("<html>")
                .append("<body>");

        response.append("<h2>Welcome, ").append(this.idToken.getClaim("email").toString()).append("</h2>\n");
        response.append("<h3>You are accessing the application within tenant <b>").append(idToken.getIssuer()).append(" boundaries</b></h3>");

        return response.append("</body>").append("</html>").toString();
    }

    /**
     * Returns the Access Token info.
     * This endpoint exists only for demonstration purposes.
     * Do not expose this token in a real application.
     *
     * @return Access Token info
     */
    @GET
    @Produces("text/html")
    @Path("bearer")
    public String getAccessTokenInfo() {
        StringBuilder response = new StringBuilder().append("<html>")
                .append("<body>");

        response.append("<h2>Welcome, ").append(this.accessToken.getClaim("email").toString()).append("</h2>\n");
        response.append("<h3>You are accessing the application within tenant <b>").append(accessToken.getIssuer()).append(" boundaries</b></h3>");

        return response.append("</body>").append("</html>").toString();
    }
}
Copy to Clipboard Toggle word wrap

要从传入请求解析租户并将其映射到 application.properties 中的特定 quarkus-oidc 租户配置,请为 io.quarkus.oidc.TenantConfigResolver 接口创建一个实现,它可以动态解析租户配置:

package org.acme.quickstart.oidc;

import jakarta.enterprise.context.ApplicationScoped;

import org.eclipse.microprofile.config.ConfigProvider;

import io.quarkus.oidc.OidcRequestContext;
import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.OidcTenantConfig.ApplicationType;
import io.quarkus.oidc.TenantConfigResolver;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomTenantResolver implements TenantConfigResolver {

    @Override
    public Uni<OidcTenantConfig> resolve(RoutingContext context, OidcRequestContext<OidcTenantConfig> requestContext) {
        String path = context.request().path();

        if (path.startsWith("/tenant-a")) {
           String keycloakUrl = ConfigProvider.getConfig().getValue("keycloak.url", String.class);

            OidcTenantConfig config = new OidcTenantConfig();
            config.setTenantId("tenant-a");
            config.setAuthServerUrl(keycloakUrl + "/realms/tenant-a");
            config.setClientId("multi-tenant-client");
            config.getCredentials().setSecret("secret");
            config.setApplicationType(ApplicationType.HYBRID);
            return Uni.createFrom().item(config);
        } else {
            // resolve to default tenant config
            return Uni.createFrom().nullItem();
        }
    }
}
Copy to Clipboard Toggle word wrap

在前面的实现中,租户是从请求路径解析的。如果没有租户推断出来,则返回 null 以指示应使用默认租户配置。

tenant-a 应用类型是 hybrid ;如果提供,它可以接受 HTTP bearer 令牌。否则,它会在需要身份验证时启动授权代码流。

5.6. 配置应用程序

# Default tenant configuration
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=multi-tenant-client
quarkus.oidc.application-type=web-app

# Tenant A configuration is created dynamically in CustomTenantConfigResolver

# HTTP security configuration
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
Copy to Clipboard Toggle word wrap

第一个配置是默认租户配置,应在无法从请求中推断租户时使用。请注意,%prod 配置集前缀与 quarkus.oidc.auth-server-url 一起使用,以支持使用 Dev Services for Keycloak 测试多租户应用程序。此配置使用 Keycloak 实例来验证用户。

当传入请求映射到 tenant-a 租户时,会使用由 TenantConfigResolver 提供的第二个配置。

这两个配置都会映射到同一 Keycloak 服务器实例,同时使用 不同的域

或者,您可以在 application.properties 中直接配置 tenant-a

# Default tenant configuration
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=multi-tenant-client
quarkus.oidc.application-type=web-app

# Tenant A configuration
quarkus.oidc.tenant-a.auth-server-url=http://localhost:8180/realms/tenant-a
quarkus.oidc.tenant-a.client-id=multi-tenant-client
quarkus.oidc.tenant-a.application-type=web-app

# HTTP security configuration
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
Copy to Clipboard Toggle word wrap

在这种情况下,也使用自定义 TenantConfigResolver 来解析它:

package org.acme.quickstart.oidc;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.oidc.TenantResolver;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomTenantResolver implements TenantResolver {

    @Override
    public String resolve(RoutingContext context) {
        String path = context.request().path();
        String[] parts = path.split("/");

        if (parts.length == 0) {
            //Resolve to default tenant configuration
            return null;
        }

        return parts[1];
    }
}
Copy to Clipboard Toggle word wrap

您可以在 配置文件中定义多个租户。要在从 TenantResolver 实现解析租户时正确映射它们,请确保每个租户都有唯一的别名。

但是,使用静态租户解析(涉及在 application.properties 中配置租户)并使用 TenantResolver 解析它们以使用 Keycloak 的 Dev Services 测试端点,因为它不知道请求如何映射到单独的租户,且无法动态提供租户特定的 quarkus.oidc.<tenant-id>.auth-server-url 值。因此,在 application.properties 中使用 %prod 前缀和特定于租户的 URL 都无法在测试和开发模式下工作。

注意

当当前租户代表 OIDC web-app 应用程序时,当前的 io.vertx.ext.web.RoutingContext 包含 tenant-id 属性,只要为完成代码身份验证流的所有请求以及已验证的、已验证的状态或会话 Cookie 都会调用 tenant-id 属性。因此,在使用多个 OIDC 供应商时,您只需要特定于路径的检查来解析租户 ID (如果 RoutingContext 没有设置 tenant-id 属性),例如:

package org.acme.quickstart.oidc;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.oidc.TenantResolver;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomTenantResolver implements TenantResolver {

    @Override
    public String resolve(RoutingContext context) {
        String tenantId = context.get("tenant-id");
        if (tenantId != null) {
            return tenantId;
        } else {
            // Initial login request
            String path = context.request().path();
            String[] parts = path.split("/");

            if (parts.length == 0) {
                //Resolve to default tenant configuration
                return null;
            }
            return parts[1];
        }
    }
}
Copy to Clipboard Toggle word wrap

如果没有注册自定义 TenantResolver,这是 Quarkus OIDC 如何解析静态自定义租户。

类似的技术可与 TenantConfigResolver 一起使用,其中上下文中提供的 tenant-id 可以返回 OidcTenantConfig 已在上一个请求中准备。

注意

如果您也 使用带有 Panache 多租户的 Hibernate ORM 多租户 或 MongoDB,并且租户 ID 相同,且必须从 Vert.x RoutingContext 中提取,您可以从 OIDC Tenant Resolver 将租户 ID 传给 Hibernate ORM Tenant Resolver 或带有 Panache Mongo Database Resolver 作为 RoutingContext 属性的 MongoDB,例如:

public class CustomTenantResolver implements TenantResolver {

    @Override
    public String resolve(RoutingContext context) {
        String tenantId = extractTenantId(context);
        context.put("tenantId", tenantId);
        return tenantId;
    }
}
Copy to Clipboard Toggle word wrap

5.7. 启动并配置 Keycloak 服务器

要启动 Keycloak 服务器,您可以使用 Docker 并运行以下命令:

docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev
Copy to Clipboard Toggle word wrap

其中 keycloak.version 设置为 24.0.0 或更高版本。

localhost:8180 访问您的 Keycloak 服务器。

admin 用户身份登录,以访问 Keycloak 管理控制台。用户名和密码都是 admin

现在,导入两个租户的域:

如需更多信息,请参阅关于如何创建新域的 Keycloak 文档。https://www.keycloak.org/docs/latest/server_admin/index.html#_create-realm

5.8. 运行并使用应用程序

5.8.1. 在开发人员模式下运行

要在 dev 模式下运行微服务,请使用:

  • 使用 Quarkus CLI:

    quarkus dev
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw quarkus:dev
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew --console=plain quarkusDev
    Copy to Clipboard Toggle word wrap

5.8.2. 在 JVM 模式下运行

在以 dev 模式探索应用后,您可以将其作为标准 Java 应用运行。

首先,编译它:

  • 使用 Quarkus CLI:

    quarkus build
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw install
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew build
    Copy to Clipboard Toggle word wrap

然后运行它:

java -jar target/quarkus-app/quarkus-run.jar
Copy to Clipboard Toggle word wrap

5.8.3. 在原生模式下运行

相同的演示可以编译到原生代码中,不需要修改。

这意味着,您不再需要在生产环境中安装 JVM,因为运行时技术包含在生成的二进制文件中,并优化以最小资源运行。

编译时间会比较较长,因此默认关闭此步骤;通过启用原生构建来再次进行构建:

  • 使用 Quarkus CLI:

    quarkus build --native
    Copy to Clipboard Toggle word wrap
  • 使用 Maven:

    ./mvnw install -Dnative
    Copy to Clipboard Toggle word wrap
  • 使用 Gradle:

    ./gradlew build -Dquarkus.package.type=native
    Copy to Clipboard Toggle word wrap

片刻后,您可以直接运行此二进制文件:

./target/security-openid-connect-multi-tenancy-quickstart-runner
Copy to Clipboard Toggle word wrap

5.9. 测试应用

5.9.1. 使用浏览器

要测试应用程序,请打开浏览器并访问以下 URL:

如果所有内容都按预期工作,您会被重定向到 Keycloak 服务器以进行身份验证。请注意,请求的路径定义了一个 默认租户,我们没有在配置文件中映射该租户。在这种情况下,会使用默认配置。

要向应用程序进行身份验证,请在 Keycloak 登录页面中输入以下凭证:

  • 用户名: alice
  • 密码 : alice

Login 按钮后,您将重新重定向到应用程序。

如果您现在尝试通过以下 URL 访问应用程序:

您再次重定向到 Keycloak 登录页面。但是,这次您要使用不同的域进行身份验证。

在这两种情况下,如果用户成功通过身份验证,则登录页面会显示用户的名称和电子邮件。虽然 alice 在两个租户中存在,但应用会将它们视为单独的域中的不同用户。

5.10. 静态租户配置解析

当您在 application.properties 文件中设置多个租户配置时,您只需要指定租户标识符的解析方式。要配置租户标识符的解析,请使用以下选项之一:

这些租户解析选项会按照列出的顺序尝试,直到租户 id 被解决为止。如果租户 id 仍然未解析(null),则会选择默认(未命名)租户配置。

5.10.1. 使用 TenantResolver解析

以下 application.properties 示例演示了如何使用 TenantResolver 方法解析名为 ab 的两个租户的租户标识符:

# Tenant 'a' configuration
quarkus.oidc.a.auth-server-url=http://localhost:8180/realms/quarkus-a
quarkus.oidc.a.client-id=client-a
quarkus.oidc.a.credentials.secret=client-a-secret

# Tenant 'b' configuration
quarkus.oidc.b.auth-server-url=http://localhost:8180/realms/quarkus-b
quarkus.oidc.b.client-id=client-b
quarkus.oidc.b.credentials.secret=client-b-secret
Copy to Clipboard Toggle word wrap

您可以从 quarkus.oidc.TenantResolver 返回 ab 的租户 ID:

import quarkus.oidc.TenantResolver;

public class CustomTenantResolver implements TenantResolver {

    @Override
    public String resolve(RoutingContext context) {
        String path = context.request().path();
        if (path.endsWith("a")) {
            return "a";
        } else if (path.endsWith("b")) {
            return "b";
        } else {
            // default tenant
            return null;
        }
    }
}
Copy to Clipboard Toggle word wrap

在本例中,最后一个请求路径片段的值是一个租户 id,但如果需要,您可以实施更复杂的租户标识符解析逻辑。

5.10.2. 默认解析

租户标识符的默认解析基于惯例,身份验证请求必须在请求路径的最后片段中包含租户标识符。

以下 application.properties 示例演示了如何配置名为 googlegithub 的两个租户:

# Tenant 'google' configuration
quarkus.oidc.google.provider=google
quarkus.oidc.google.client-id=${google-client-id}
quarkus.oidc.google.credentials.secret=${google-client-secret}
quarkus.oidc.google.authentication.redirect-path=/signed-in

# Tenant 'github' configuration
quarkus.oidc.github.provider=google
quarkus.oidc.github.client-id=${github-client-id}
quarkus.oidc.github.credentials.secret=${github-client-secret}
quarkus.oidc.github.authentication.redirect-path=/signed-in
Copy to Clipboard Toggle word wrap

在提供的示例中,两个租户都将 OIDC web-app 应用程序配置为使用授权代码流来验证用户,并在身份验证后生成会话 Cookie。在 Google 或 GitHub 验证当前用户后,用户将返回到经过身份验证的用户的 /signed-in 区域,如 JAX-RS 端点上的安全资源路径。

最后,要完成默认租户解析,请设置以下配置属性:

quarkus.http.auth.permission.login.paths=/google,/github
quarkus.http.auth.permission.login.policy=authenticated
Copy to Clipboard Toggle word wrap

如果端点在 http://localhost:8080 上运行,您也可以为用户提供登录到 http://localhost:8080/googlehttp://localhost:8080/github 的 UI 选项,而无需添加特定的 /google/github JAX-RS 资源路径。身份验证完成后,租户标识符也会记录在会话 Cookie 名称中。因此,经过身份验证的用户可以访问安全应用程序区域,而无需将 googlegithub 路径值包含在安全 URL 中。

默认解析也可以用于 Bearer 令牌身份验证。仍然可能不太实际,因为租户标识符必须始终设置为最后一个路径片段值。

5.10.3. 使用注解解析

您可以使用 io.quarkus.oidc.Tenant 注解来解析租户标识符,作为使用 io.quarkus.oidc.TenantResolver 的替代选择。

注意

必须禁用主动 HTTP 身份验证(quarkus.http.auth.proactive=false)才能使它正常工作。如需更多信息,请参阅 主动身份验证 指南。

假设应用程序支持两个 OIDC 租户( hr 和 default 租户),所有带 @Tenant ("hr") 的资源方法和类都通过使用 quarkus.oidc.hr.auth-server-url 配置的 OIDC 供应商进行身份验证。相反,所有其他类和方法仍然通过使用默认 OIDC 供应商进行身份验证。

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

import io.quarkus.oidc.Tenant;
import io.quarkus.security.Authenticated;

@Authenticated
@Path("/api/hello")
public class HelloResource {

    @Tenant("hr") 
1

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHello() {
        return "Hello!";
    }
}
Copy to Clipboard Toggle word wrap
1
io.quarkus.oidc.Tenant 注解必须放在资源类或资源方法上。

5.11. 动态租户配置解析

如果您需要为需要支持的不同租户进行更多动态配置,且不想与配置文件中的多个条目结束,您可以使用 io.quarkus.oidc.TenantConfigResolver

此接口允许您在运行时动态创建租户配置:

package io.quarkus.it.keycloak;

import jakarta.enterprise.context.ApplicationScoped;
import java.util.function.Supplier;

import io.smallrye.mutiny.Uni;
import io.quarkus.oidc.OidcRequestContext;
import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.TenantConfigResolver;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomTenantConfigResolver implements TenantConfigResolver {

    @Override
    public Uni<OidcTenantConfig> resolve(RoutingContext context, OidcRequestContext<OidcTenantConfig> requestContext) {
        String path = context.request().path();
        String[] parts = path.split("/");

        if (parts.length == 0) {
            //Resolve to default tenant configuration
            return null;
        }

        if ("tenant-c".equals(parts[1])) {
            // Do 'return requestContext.runBlocking(createTenantConfig());'
            // if a blocking call is required to create a tenant config,
            return Uni.createFromItem(createTenantConfig());
        }

        //Resolve to default tenant configuration
        return null;
    }

    private Supplier<OidcTenantConfig> createTenantConfig() {
        final OidcTenantConfig config = new OidcTenantConfig();

        config.setTenantId("tenant-c");
        config.setAuthServerUrl("http://localhost:8180/realms/tenant-c");
        config.setClientId("multi-tenant-client");
        OidcTenantConfig.Credentials credentials = new OidcTenantConfig.Credentials();

        credentials.setSecret("my-secret");

        config.setCredentials(credentials);

        // Any other setting supported by the quarkus-oidc extension

        return () -> config;
    }
}
Copy to Clipboard Toggle word wrap

此方法返回的 OidcTenantConfig 与从 application.properties 解析 oidc 命名空间配置的方式相同。您可以使用 quarkus-oidc 扩展支持的任何设置来填充它。

如果动态租户解析器返回 null,则下一步会尝试 静态租户配置解析

5.11.1. OIDC web-app 应用程序的租户解析

解析 OIDC web-app 应用程序配置的最简单选项是按照 Default resolution 部分中描述的步骤进行操作。

如果默认解析策略不适用于应用程序设置,请尝试以下其中一个选项。

有几个选项可用于选择租户配置,这些配置应该用来保护 服务和 web-app OIDC 应用程序的当前 HTTP 请求,例如:

  • 检查 URL 路径。例如,tenant-service 配置必须用于 /service 路径,而 tenant-manage 配置必须用于 /management 路径。
  • 检查 HTTP 标头。例如,如果 URL 路径始终为 /service,一个标头(如 Realm: serviceRealm: 管理 )可帮助选择 tenant-servicetenant-manage 配置。
  • 检查 URL 查询参数。它的工作方式与标头用于选择租户配置的方式类似。

所有这些选项都可以使用 OIDC 服务 应用程序的 custom TenantResolverTenantConfigResolver 实现轻松实现。

但是,由于 HTTP 重定向需要完成 OIDC web-app 应用程序的代码身份验证流,可能需要自定义 HTTP cookie 以在此重定向请求前后选择相同的租户配置,因为:

  • 如果在 OIDC 供应商中注册了单个重定向 URL,在重定向请求后 URL 路径可能不同。在租户配置解决后,可以恢复原始请求路径。
  • 重定向后,原始请求中使用的 HTTP 标头不可用。
  • 自定义 URL 查询参数在重定向后恢复,但仅在租户配置解决后恢复。

其中一个选项是确保解析 web-app 应用程序的租户配置的信息在重定向之前和之后可用,例如:

package org.acme.quickstart.oidc;

import java.util.List;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.oidc.TenantResolver;
import io.vertx.core.http.Cookie;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomTenantResolver implements TenantResolver {

    @Override
    public String resolve(RoutingContext context) {
        List<String> tenantIdQuery = context.queryParam("tenantId");
        if (!tenantIdQuery.isEmpty()) {
            String tenantId = tenantIdQuery.get(0);
            context.response().addCookie(Cookie.cookie("tenant", tenantId));
            return tenantId;
        } else if (!context.request().cookies("tenant").isEmpty()) {
            return context.request().getCookie("tenant").getValue();
        }

        return null;
    }
}
Copy to Clipboard Toggle word wrap

5.12. 禁用租户配置

如果没有可以从当前请求中推断租户,并且需要回退到默认租户配置,则自定义 TenantResolverTenantConfigResolver 实现可能会返回 null

如果您期望自定义解析器始终解析租户,则不需要配置默认租户解析。

  • 要关闭默认租户配置,请设置 quarkus.oidc.tenant-enabled=false
注意

quarkus.oidc.auth-server-url 没有配置时,默认的租户配置会被自动禁用,但自定义租户配置可用,或者为 TenantConfigResolver 注册。

请注意,特定于租户的配置也可以禁用,例如: quarkus.oidc.tenant-a.tenant-enabled=false

5.13. 参考

第 6 章 OpenID Connect (OIDC)配置属性

作为 Quarkus 开发人员,您可以通过在 src/main/resources/application.properties 文件中设置以下属性来配置 Quarkus OpenID Connect (OIDC)扩展。

lock 构建时修复的配置属性 - 所有其他配置属性可在运行时覆盖

Expand

类型

default

lock quarkus.keycloak.devservices.enabled

用于启用(默认)或禁用 Dev 服务的标志。启用后,Keycloak 的 Dev Services 会在 Dev 或 Test 模式中自动配置并启动 Keycloak,以及 Docker 运行时。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_ENABLED

布尔值

true

lock quarkus.keycloak.devservices.image-name

Dev Services 供应商的容器镜像名称。默认为基于 Quarkus 的 Keycloak 镜像。对于基于 WildFly 的发布,请使用 quay.io/keycloak/keycloak:19.0.3-legacy 等镜像。Keycloak Quarkus 和 WildFly 镜像会以不同的方式初始化。用于 Keycloak 的 dev Services 将假定它是一个 Keycloak Quarkus 镜像,除非镜像版本以 -legacy 结尾。使用 quarkus.keycloak.devservices.keycloak-x-image 覆盖。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_IMAGE_NAME

string

quay.io/keycloak/keycloak:24.0.4

lock quarkus.keycloak.devservices.keycloak-x-image

指明是否使用 Keycloak-X 镜像。默认情况下,镜像由镜像名称中的 keycloak-x 标识。对于自定义镜像,使用 quarkus.keycloak.devservices.keycloak-x-image 覆盖。如果默认检查正常工作,则不需要设置此属性。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_KEYCLOAK_X_IMAGE

布尔值

 

lock quarkus.keycloak.devservices.shared

确定 Keycloak 容器是否已共享。共享时,Quarkus 使用基于标签的服务发现来查找和重复使用正在运行的 Keycloak 容器,因此没有启动第二个容器。否则,如果没有找到匹配的容器,则会启动一个新容器。服务发现使用 quarkus-dev-service-label 标签,其值由 service-name 属性设置。容器共享仅以 dev 模式提供。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_SHARED

布尔值

true

lock quarkus.keycloak.devservices.service-name

quarkus-dev-service-keycloak 标签的值,用于标识 Keycloak 容器。用于共享模式,以查找具有此标签的现有容器。如果没有找到,则使用此标签初始化一个新容器。仅适用于 dev 模式。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_SERVICE_NAME

string

Quarkus

lock quarkus.keycloak.devservices.realm-path

以逗号分隔的到 Keycloak 域文件的类或文件系统路径列表。此列表用于初始化 Keycloak。此列表中的第一个值用于初始化默认租户连接属性。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_REALM_PATH

字符串列表

 

lock quarkus.keycloak.devservices.java-opts

传递给 keycloak JVM 的 JAVA_OPTS

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_JAVA_OPTS

string

 

lock quarkus.keycloak.devservices.show-logs

显示带有 "Keycloak:" 前缀的 Keycloak 日志消息。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_SHOW_LOGS

布尔值

false

lock quarkus.keycloak.devservices.start-command

Keycloak start 命令。使用此属性试验 Keycloak 启动选项,请参阅 https://www.keycloak.org/server/all-config。请注意,在载入旧的 Keycloak WildFly 镜像时会忽略它。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_START_COMMAND

string

 

lock quarkus.keycloak.devservices.realm-name

Keycloak 域的名称。如果 realm-path 属性指向的域,则此属性用于创建域。在本例中,默认值为 quarkus。建议始终设置此属性,以便 Keycloak 的 Dev Services 可以识别域名称,而无需解析域文件。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_REALM_NAME

string

 

lock quarkus.keycloak.devservices.create-realm

指定是否在 realm-path 上找不到域文件时创建 Keycloak 域。如果要使用 Keycloak 管理控制台或 io.quarkus.test.common.QuarkusTestResourceLifecycleManager 提供的 Keycloak Admin API 创建域,则设置为 false

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_CREATE_REALM

布尔值

true

lock quarkus.keycloak.devservices.port

要侦听的 dev 服务的具体端口。

如果没有指定,则会选择一个随机端口。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_PORT

int

 

lock quarkus.keycloak.devservices.resource-aliases

用于初始化 Keycloak 的额外类或文件系统资源的别名。每个映射条目代表别名和类或文件系统资源路径之间的映射。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_RESOURCE_ALIASES

Map<String,String>

 

lock quarkus.keycloak.devservices.resource-mappings

用于初始化 Keycloak 的其他类或文件系统资源。每个映射条目代表类或文件系统资源路径别名和 Keycloak 容器位置之间的映射。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_RESOURCE_MAPPINGS

Map<String,String>

 

lock quarkus.keycloak.devservices.users

Keycloak 用户名与密码映射。如果为空,则创建默认用户 alicebob,其名称用作密码。当 realm-path 没有找到 realm 文件时,这个映射用于用户创建。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_USERS

Map<String,String>

 

lock quarkus.keycloak.devservices.roles

Keycloak 用户的角色映射。如果为空,则分配默认角色: alice 接收 admin用户角色,而其他用户则收到 用户角色。当 realm-path 没有找到 realm 文件时,此映射用于创建角色。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_ROLES

Map<String,List<String>>

 

lock quarkus.keycloak.devservices.container-env

要传递给容器的环境变量。

环境变量: QUARKUS_KEYCLOAK_DEVSERVICES_CONTAINER_ENV

Map<String,String>

 

lock quarkus.oidc.enabled

如果启用了 OIDC 扩展。

环境变量: QUARKUS_OIDC_ENABLED

布尔值

true

lock quarkus.oidc.devui.grant.type

授权类型,用于获取令牌来测试 OIDC 'service' 应用程序

环境变量: QUARKUS_OIDC_DEVUI_GRANT_TYPE

工具提示:client['client_credentials' grant], tooltip:password['password' grant], tooltip:code['authorization_code' grant], tooltip:implicit['implicit' grant]

 

lock quarkus.oidc.devui.web-client-timeout

WebClient 超时。使用此属性配置 Dev UI 处理程序使用的 HTTP 客户端在从 OpenId Connect Provider 请求令牌并将其发送到服务端点时,将等待响应。OIDC dev 服务管理客户端也使用此超时。

环境变量: QUARKUS_OIDC_DEVUI_WEB_CLIENT_TIMEOUT

duration question circle

4S

lock quarkus.oidc.default-token-cache-enabled

启用注册 Default TokenIntrospection 和 UserInfo Cache 实现 bean。注: 这仅启用默认的实施。它需要激活配置。请参阅 OidcConfig#tokenCache

环境变量: QUARKUS_OIDC_DEFAULT_TOKEN_CACHE_ENABLED

布尔值

true

quarkus.oidc.auth-server-url

OpenID Connect (OIDC)服务器的基本 URL,例如 https://host:port/auth。如果需要公钥验证(公钥)或仅需要证书链验证(certificate-chain),则不要设置此属性。默认情况下,OIDC 发现端点会在这个 URL 中附加 .well-known/openid-configuration 路径来调用。对于 Keycloak,使用 https://host:port/realms/{realm},将 {realm} 替换为 Keycloak 域名。

环境变量: QUARKUS_OIDC_AUTH_SERVER_URL

string

 

quarkus.oidc.discovery-enabled

发现 OIDC 端点。如果没有启用,您必须单独配置 OIDC 端点 URL。

环境变量: QUARKUS_OIDC_DISCOVERY_ENABLED

布尔值

true

quarkus.oidc.token-path

签发访问和刷新令牌的 OIDC 令牌端点;指定为相对路径或绝对 URL。如果 discovery-enabledfalse,或必须自定义发现的令牌端点路径。

环境变量: QUARKUS_OIDC_TOKEN_PATH

string

 

quarkus.oidc.revoke-path

OIDC 令牌撤销端点的相对路径或绝对路径 URL。

环境变量: QUARKUS_OIDC_REVOKE_PATH

string

 

quarkus.oidc.client-id

应用程序的客户端 ID。每个应用都有一个客户端 ID,用于标识应用程序。如果 application-typeservice,且不需要令牌内省,则不需要设置客户端 ID。

环境变量: QUARKUS_OIDC_CLIENT_ID

string

 

quarkus.oidc.connection-delay

尝试初始连接到 OIDC 服务器的持续时间。例如,将持续时间设置为 20S 允许 10 次重试,每 2 秒。此属性仅在创建初始 OIDC 连接时才有效。对于丢弃的连接,请使用 connection-retry-count 属性。

环境变量: QUARKUS_OIDC_CONNECTION_DELAY

duration question circle

 

quarkus.oidc.connection-retry-count

如果临时丢失,重试重新建立现有 OIDC 连接的次数。与 connection-delay 不同,它只适用于初始连接尝试。例如,如果对 OIDC 令牌端点的请求因为连接问题而失败,它将按此设置重试。

环境变量: QUARKUS_OIDC_CONNECTION_RETRY_COUNT

int

3

quarkus.oidc.connection-timeout

当前 OIDC 连接请求超时的秒数。

环境变量: QUARKUS_OIDC_CONNECTION_TIMEOUT

duration question circle

10S

quarkus.oidc.use-blocking-dns-lookup

是否应该在 worker 线程上执行 DNS 查找。当您可以参阅 HTTP 请求到 OIDC 服务器来记录有关阻止的 Vert.x 事件循环的日志记录警告时,请使用这个选项。

环境变量: QUARKUS_OIDC_USE_BLOCKING_DNS_LOOKUP

布尔值

false

quarkus.oidc.max-pool-size

WebClient 使用的连接池的最大大小。

环境变量: QUARKUS_OIDC_MAX_POOL_SIZE

int

 

quarkus.oidc.credentials.secret

client_secret_basic 身份验证方法使用的客户端 secret。必须设置,除非需要在 client-secretjwt 客户端身份验证中设置 secret。您可以使用 client-secret.value,但这两个属性都是互斥的。

环境变量: QUARKUS_OIDC_CREDENTIALS_SECRET

string

 

quarkus.oidc.credentials.client-secret.value

客户端机密值。如果设置了 credentials.secret,则忽略这个值。必须设置,除非需要在 client-secretjwt 客户端身份验证中设置 secret。

环境变量: QUARKUS_OIDC_CREDENTIALS_CLIENT_SECRET_VALUE

string

 

quarkus.oidc.credentials.client-secret.provider.name

CredentialsProvider 名称,只有在注册了多个 CredentialsProvider 时才应设置

环境变量: QUARKUS_OIDC_CREDENTIALS_CLIENT_SECRET_PROVIDER_NAME

string

 

quarkus.oidc.credentials.client-secret.provider.key

CredentialsProvider 客户端 secret 密钥

环境变量: QUARKUS_OIDC_CREDENTIALS_CLIENT_SECRET_PROVIDER_KEY

string

 

quarkus.oidc.credentials.client-secret.method

身份验证方法。如果设置了 clientSecret.value secret,则此方法默认是 基本的

环境变量: QUARKUS_OIDC_CREDENTIALS_CLIENT_SECRET_METHOD

工具提示:basic[client_secret_basic (默认): 客户端 ID 和 secret 使用 HTTP 授权基本方案提交。],工具提示:post[ client_secret_ post : 客户端 ID 和 secret 作为 client _ id 和 client _secret 表单参数提交。],工具提示:post-jwt[ client_secret _jwt : 客户端 ID 和生成的 JWT secret 作为 client _id 和 client_secret 表格参数提交。],工具提示:query[client id 和 secret 作为 HTTP 查询参数提交。这个选项只支持 OIDC 扩展。]

 

quarkus.oidc.credentials.jwt.secret

如果提供,则表示 JWT 使用 secret 密钥进行了签名。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_SECRET

string

 

quarkus.oidc.credentials.jwt.secret-provider.name

CredentialsProvider 名称,只有在注册了多个 CredentialsProvider 时才应设置

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_SECRET_PROVIDER_NAME

string

 

quarkus.oidc.credentials.jwt.secret-provider.key

CredentialsProvider 客户端 secret 密钥

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_SECRET_PROVIDER_KEY

string

 

quarkus.oidc.credentials.jwt.key-file

如果提供,则表示 JWT 是使用 PEM 或 JWK 格式的私钥签名的。您可以使用 signature-algorithm 属性覆盖默认的密钥算法 RS256

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_KEY_FILE

string

 

quarkus.oidc.credentials.jwt.key-store-file

如果提供,则表示 JWT 使用密钥存储中的私钥签名。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_KEY_STORE_FILE

string

 

quarkus.oidc.credentials.jwt.key-store-password

指定密钥存储文件的密码的参数。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_KEY_STORE_PASSWORD

string

 

quarkus.oidc.credentials.jwt.key-id

私钥 ID 或别名。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_KEY_ID

string

 

quarkus.oidc.credentials.jwt.key-password

私钥密码。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_KEY_PASSWORD

string

 

quarkus.oidc.credentials.jwt.audience

JWT 受众(ud)声明值。默认情况下,audience 设置为 OpenId Connect Provider 的令牌端点的地址。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_AUDIENCE

string

 

quarkus.oidc.credentials.jwt.token-key-id

添加为 JWT kid 标头的签名密钥标识符。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_TOKEN_KEY_ID

string

 

quarkus.oidc.credentials.jwt.issuer

添加为 JWT 的签名密钥的签发者 是s 声明。默认值为客户端 ID。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_ISSUER

string

 

quarkus.oidc.credentials.jwt.subject

添加为 JWT 声明的签名密钥的主题。默认值是客户端 ID。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_SUBJECT

string

 

quarkus.oidc.credentials.jwt.signature-algorithm

用于 key-file 属性的签名算法。支持的值有: RS256 (默认)、RS384RS512PS256PS384PS512、ES256、ES256ES384、ES512、ES512、ES512、ESS256HS384HS512.

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_SIGNATURE_ALGORITHM

string

 

quarkus.oidc.credentials.jwt.lifespan

JWT 生命周期(以秒为单位)。这个值添加到发出 JWT 的时间,以计算过期时间。

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_LIFESPAN

int

10

quarkus.oidc.proxy.host

代理的主机名或 IP 地址。
注: 如果 OIDC 适配器需要代理与 OIDC 服务器(Provider)通信,请将此值设置为以启用代理的使用。

环境变量: QUARKUS_OIDC_PROXY_HOST

string

 

quarkus.oidc.proxy.port

代理的端口号。默认值为 80

环境变量: QUARKUS_OIDC_PROXY_PORT

int

80

quarkus.oidc.proxy.username

如果代理需要身份验证,则用户名。

环境变量: QUARKUS_OIDC_PROXY_USERNAME

string

 

quarkus.oidc.proxy.password

如果代理需要身份验证,则密码。

环境变量: QUARKUS_OIDC_PROXY_PASSWORD

string

 

quarkus.oidc.tls.verification

证书验证和主机名验证,可以是以下 验证值之一。默认为

环境变量: QUARKUS_OIDC_TLS_VERIFICATION

工具提示:required[Certificates 被验证,并且启用了主机名验证。这是默认的 value.],工具提示:certificate-validation[Certificates 被验证,但主机名验证为 disabled.],提示提示:none[All 证书是可信的,主机名验证被禁用。]

 

quarkus.oidc.tls.key-store-file

保存证书信息的可选密钥存储,而不是指定单独的文件。

环境变量: QUARKUS_OIDC_TLS_KEY_STORE_FILE

path

 

quarkus.oidc.tls.key-store-file-type

密钥存储文件的类型。如果未指定,则根据文件名自动检测到类型。

环境变量: QUARKUS_OIDC_TLS_KEY_STORE_FILE_TYPE

string

 

quarkus.oidc.tls.key-store-provider

密钥存储文件的提供程序。如果未指定,则根据密钥存储文件类型自动检测到该提供程序。

环境变量: QUARKUS_OIDC_TLS_KEY_STORE_PROVIDER

string

 

quarkus.oidc.tls.key-store-password

密钥存储文件的密码。如果未指定,则使用默认值,即 密码

环境变量: QUARKUS_OIDC_TLS_KEY_STORE_PASSWORD

string

 

quarkus.oidc.tls.key-store-key-alias

密钥存储中特定密钥的别名。禁用 SNI 时,如果密钥存储包含多个密钥且没有指定别名,则行为未定义。

环境变量: QUARKUS_OIDC_TLS_KEY_STORE_KEY_ALIAS

string

 

quarkus.oidc.tls.key-store-key-password

密钥的密码(如果与 key-store-password 不同)。

环境变量: QUARKUS_OIDC_TLS_KEY_STORE_KEY_PASSWORD

string

 

quarkus.oidc.tls.trust-store-file

保存要信任的证书信息的信任存储。

环境变量: QUARKUS_OIDC_TLS_TRUST_STORE_FILE

path

 

quarkus.oidc.tls.trust-store-password

truststore 文件的密码。

环境变量: QUARKUS_OIDC_TLS_TRUST_STORE_PASSWORD

string

 

quarkus.oidc.tls.trust-store-cert-alias

信任存储证书的别名。

环境变量: QUARKUS_OIDC_TLS_TRUST_STORE_CERT_ALIAS

string

 

quarkus.oidc.tls.trust-store-file-type

truststore 文件的类型。如果未指定,则根据文件名自动检测到类型。

环境变量: QUARKUS_OIDC_TLS_TRUST_STORE_FILE_TYPE

string

 

quarkus.oidc.tls.trust-store-provider

truststore 文件的供应商。如果没有提供,则会根据信任存储文件类型自动检测到供应商。

环境变量: QUARKUS_OIDC_TLS_TRUST_STORE_PROVIDER

string

 

quarkus.oidc.tenant-id

唯一的租户标识符。它可以由 TenantConfigResolver 提供程序设置,后者可以动态解析租户配置。

环境变量: QUARKUS_OIDC_TENANT_ID

string

 

quarkus.oidc.tenant-enabled

如果启用了此租户配置。如果没有配置,但支持租户配置的 TenantConfigResolver,则默认租户会被禁用,或者配置了命名的租户。在这种情况下,您不需要禁用默认租户。

环境变量: QUARKUS_OIDC_TENANT_ENABLED

布尔值

true

quarkus.oidc.application-type

应用程序类型,可以是以下 ApplicationType 值之一。

环境变量: QUARKUS_OIDC_APPLICATION_TYPE

工具提示:web-app[A WEB_APP 是提供页面(通常是前端应用程序)的客户端。对于这种类型的客户端,Authorization Code Flow 定义为验证用户的首选方法。],工具提示:service[A SERVICE 是一个具有一组受保护的 HTTP 资源的客户端,通常是遵循 RESTful 架构师设计的后端服务。对于这种类型的客户端,Bearer Authorization 方法定义为身份验证和授权用户的首选方法。],工具提示:hybrid[A combined SERVICEWEB_APP 客户端。对于这种类型的客户端,如果设置了 Authorization 标头和 Authorization Code Flow - 如果不是,则使用 Bearer Authorization 方法。]

service

quarkus.oidc.authorization-path

OpenID Connect (OIDC)授权端点的相对路径或绝对 URL,用于验证用户。如果 OIDC 发现被禁用,则必须为 web-app 应用程序设置此属性。如果启用了 OIDC 发现,则忽略此属性。

环境变量: QUARKUS_OIDC_AUTHORIZATION_PATH

string

 

quarkus.oidc.user-info-path

OIDC UserInfo 端点的相对路径或绝对路径 URL。如果 OIDC 发现被禁用并且启用了 authentication.user-info-required 属性,则必须为 web-app 应用程序设置此属性。如果启用了 OIDC 发现,则忽略此属性。

环境变量: QUARKUS_OIDC_USER_INFO_PATH

string

 

quarkus.oidc.introspection-path

OIDC RFC7662 内省端点的相对路径或绝对路径 URL,这些端点可以内省不透明和 JSON Web 令牌(JWT)令牌。如果禁用了 OIDC 发现,并且必须验证不透明 bearer 访问令牌,或 2)当缓存的 JWK 验证集没有匹配的 JWK 验证集时,必须设置此属性。如果启用了发现,则忽略此属性。

环境变量: QUARKUS_OIDC_INTROSPECTION_PATH

string

 

quarkus.oidc.jwks-path

返回 JSON Web 密钥验证集的 OIDC JSON Web Key Set (JWKS)端点的相对路径或绝对路径。如果禁用了 OIDC 发现且需要本地 JWT 验证,则应设置此属性。如果启用了发现,则忽略此属性。

环境变量: QUARKUS_OIDC_JWKS_PATH

string

 

quarkus.oidc.end-session-path

OIDC end_session_endpoint 的相对路径或绝对路径 URL。如果禁用了 OIDC 发现,并且需要对 web-app 应用程序的 RP Initiated Logout 支持,则必须设置此属性。如果启用了发现,则忽略此属性。

环境变量: QUARKUS_OIDC_END_SESSION_PATH

string

 

quarkus.oidc.public-key

本地 JWT 令牌验证的公钥。当设置此属性时,不会创建 OIDC 服务器连接。

环境变量: QUARKUS_OIDC_PUBLIC_KEY

string

 

quarkus.oidc.introspection-credentials.name

Name

环境变量: QUARKUS_OIDC_INTROSPECTION_CREDENTIALS_NAME

string

 

quarkus.oidc.introspection-credentials.secret

Secret

环境变量: QUARKUS_OIDC_INTROSPECTION_CREDENTIALS_SECRET

string

 

quarkus.oidc.introspection-credentials.include-client-id

包含使用 quarkus.oidc.client-id 配置的 OpenId Connect Client ID。

环境变量: QUARKUS_OIDC_INTROSPECTION_CREDENTIALS_INCLUDE_CLIENT_ID

布尔值

true

quarkus.oidc.roles.role-claim-path

包含组数组的声明的路径列表。每个路径从顶级 JWT JSON 对象开始,并可以包含多个片段。每个片段仅代表一个 JSON 对象名称,例如:"realm/groups"。使用带命名空间限定声明名称的双引号。如果令牌没有 声明,但有一个或多个不同声明中设置的组,则可以使用此属性。

环境变量: QUARKUS_OIDC_ROLES_ROLE_CLAIM_PATH

字符串列表

 

quarkus.oidc.roles.role-claim-separator

包含多个组值的字符串的分隔符。只有在 "role-claim-path" 属性指向值为字符串的一个或多个自定义声明时才使用它。默认情况下会使用单个空格,因为标准 范围 声明可以包含空格分隔的序列。

环境变量: QUARKUS_OIDC_ROLES_ROLE_CLAIM_SEPARATOR

string

 

quarkus.oidc.roles.source

主体角色的源。

环境变量: QUARKUS_OIDC_ROLES_SOURCE

工具提示:idtoken[ID Token - web-app applications.], tooltip:accesstoken[Access Token - 服务 应用程序的默认值; 也可以用作 web-app application.], 工具提示:userinfo[User Info] 的角色源。

 

quarkus.oidc.token.issuer

预期的签发者 是声明 值。此属性覆盖 issuer 属性,它可能会在 OpenId Connect 供应商已知的配置中设置。如果 iss claim 值因提供程序的主机、IP 地址或租户 ID 不同,您可以通过将此属性设置为 任何 来跳过签发者验证,但应仅在其他选项(如配置提供程序使用固定声明值)时执行。

环境变量: QUARKUS_OIDC_TOKEN_ISSUER

string

 

quarkus.oidc.token.audience

预期 受众 的声明值,可以是字符串或字符串数组。请注意,默认情况下,验证了 audience 声明 ID 令牌。ID 令牌使用者必须等于 quarkus.oidc.client-id 属性的值。如果您的 OpenID Connect 供应商在 ID 令牌中设置不同的 audience 声明值,请使用此属性覆盖预期的值。如果您的供应商没有设置 ID 令牌使用者的声明,则将其设置为 任何。只有在配置了此属性时,才会对访问令牌进行使用者验证。

环境变量: QUARKUS_OIDC_TOKEN_AUDIENCE

字符串列表

 

quarkus.oidc.token.subject-required

要求令牌包含 sub (subject)声明,它是当前用户的唯一且永远不会重新分配的标识符。请注意,如果您启用此属性,并且还需要 UserInfo,则必须存在 token 和 UserInfo 声明,并相互匹配。

环境变量: QUARKUS_OIDC_TOKEN_SUBJECT_REQUIRED

布尔值

false

quarkus.oidc.token.token-type

预期的令牌类型

环境变量: QUARKUS_OIDC_TOKEN_TOKEN_TYPE

string

 

quarkus.oidc.token.lifespan-grace

生命周期跨宽限期(以秒为单位)。在检查令牌到期时,允许当前的时间超过令牌过期时间(最多配置的秒数)。在检查令牌颁发时,当前时间最多允许于令牌问题时间超过配置的秒数。

环境变量: QUARKUS_OIDC_TOKEN_LIFESPAN_GRACE

int

 

quarkus.oidc.token.age

令牌期限.它可指定自 iat (在)时间后不得经过的秒数。一个小的用于时钟偏移的 leeway,它可以使用 quarkus.oidc.token.lifespan-grace 来配置,以验证令牌到期时间也可以用于验证令牌年龄属性。请注意,设置此属性不会放宽 Bearer 和代码流 JWT 令牌必须具有有效的(exp)到期声明值的要求。设置此属性放松需要的唯一例外是,当注销令牌与后端退出请求发送时,因为当前的 OpenId Connect Back-Channel 规格没有明确要求包含 exp 声明。但是,即使当前注销令牌没有 exp 声明,仍然会在注销令牌包含该令牌时验证 exp 声明。

环境变量: QUARKUS_OIDC_TOKEN_AGE

duration question circle

 

quarkus.oidc.token.principal-claim

包含主体名称的声明的名称。默认情况下,会检查 upnpreferred_usernamesub 声明。

环境变量: QUARKUS_OIDC_TOKEN_PRINCIPAL_CLAIM

string

 

quarkus.oidc.token.refresh-expired

刷新已过期的授权代码流 ID 或访问令牌。如果启用了此属性,如果授权代码 ID 或访问令牌已过期,则会执行刷新令牌请求,如果成功,本地会话会使用新的令牌集合更新。否则,本地会话将无效,用户重定向到 OpenID 提供程序以重新进行身份验证。在这种情况下,如果 OIDC 供应商会话仍然活跃,用户可能无法再次挑战。对于此选项,password _session-age-extension 属性也应设置为非零值,因为刷新令牌当前保留在用户会话中。只有在应用程序类型为 ApplicationType#WEB_APP} 时,这个选项才有效。如果配置了 quarkus.oidc.token.refresh-token-time-skew,则不需要在本例中手动启用此属性。

环境变量: QUARKUS_OIDC_TOKEN_REFRESH_EXPIRED

布尔值

false

quarkus.oidc.token.refresh-token-time-skew

刷新令牌时间偏移(以秒为单位)。如果启用了此属性,在检查授权代码 ID 或访问令牌是否应刷新时,配置的秒数会添加到当前时间。如果总和大于授权代码 ID 或访问令牌的过期时间,则会进行刷新。

环境变量: QUARKUS_OIDC_TOKEN_REFRESH_TOKEN_TIME_SKEW

duration question circle

 

quarkus.oidc.token.forced-jwk-refresh-interval

强制 JWK 设置刷新间隔(以分钟为单位)。

环境变量: QUARKUS_OIDC_TOKEN_FORCED_JWK_REFRESH_INTERVAL

duration question circle

10M

quarkus.oidc.token.header

包含 bearer 令牌的自定义 HTTP 标头。只有在应用程序类型为 ApplicationType CPUfreqSERVICE } 时,这个选项才有效。

环境变量: QUARKUS_OIDC_TOKEN_HEADER

string

 

quarkus.oidc.token.authorization-scheme

HTTP 授权标头方案.

环境变量: QUARKUS_OIDC_TOKEN_AUTHORIZATION_SCHEME

string

bearer

quarkus.oidc.token.signature-algorithm

所需的签名算法。OIDC 供应商支持许多签名算法,但如果需要,您可以限制 Quarkus 应用程序来接受仅使用此属性配置的算法签名的令牌。

环境变量: QUARKUS_OIDC_TOKEN_SIGNATURE_ALGORITHM

rs256,rs 384,rs512,ps256,ps384,ps512,es256,es384,es512,edsa

 

quarkus.oidc.token.decryption-key-location

解密密钥位置.JWT 令牌可由 OpenId Connect 提供程序进行内部签名和加密。但是,并不总是能够远程内省此类令牌,因为提供程序可能无法控制私钥。在这种情况下,将此属性设置为指向包含 PEM 或 JSON Web 密钥(JWK)格式的解密私钥的文件。如果没有设置此属性,并且使用了 private_key_jwt 客户端身份验证方法,则用于为客户端身份验证 JWT 令牌签名的私钥也用于解密加密的 ID 令牌。

环境变量: QUARKUS_OIDC_TOKEN_DECRYPTION_KEY_LOCATION

string

 

quarkus.oidc.token.allow-jwt-introspection

当没有匹配的 JWK 密钥时,允许远程内省 JWT 令牌。出于向后兼容性的原因,此属性默认设置为 true。计划在以后的发行版本中,此默认值将更改为 false。另请注意,如果 JWK 端点 URI 不可用并且内省令牌是唯一验证选项,则此属性将被忽略。

环境变量: QUARKUS_OIDC_TOKEN_ALLOW_JWT_INTROSPECTION

布尔值

true

quarkus.oidc.token.require-jwt-introspection-only

要求仅远程内省 JWT 令牌。

环境变量: QUARKUS_OIDC_TOKEN_REQUIRE_JWT_INTROSPECTION_ONLY

布尔值

false

quarkus.oidc.token.allow-opaque-token-introspection

允许远程内省不透明令牌。如果只有 JWT 令牌,则将此属性设置为 false

环境变量: QUARKUS_OIDC_TOKEN_ALLOW_OPAQUE_TOKEN_INTROSPECTION

布尔值

true

quarkus.oidc.token.customizer-name

令牌自定义器名称。允许选择特定于租户的令牌自定义器作为命名 Bean。在注册自定义令牌时,首选使用 Tenant Feature qualifier。使用此属性只引用此扩展提供的 TokenCustomizer 实现。

环境变量: QUARKUS_OIDC_TOKEN_CUSTOMIZER_NAME

string

 

quarkus.oidc.token.verify-access-token-with-user-info

间接验证不透明(二进制)访问令牌是否有效,方法是请求 UserInfo。如果提供商接受此令牌并返回有效的 UserInfo,则不透明访问令牌被视为有效。只有在必须接受不透明访问令牌但 OpenId Connect 供应商没有令牌内省端点时,才应启用此选项。当必须验证 JWT 令牌时,此属性无效。

环境变量: QUARKUS_OIDC_TOKEN_VERIFY_ACCESS_TOKEN_WITH_USER_INFO

布尔值

false

quarkus.oidc.logout.path

应用程序上 logout 端点的相对路径。如果提供,应用程序可以通过此端点启动注销,并符合 OpenID Connect RP-Initiated Logout 规格。

环境变量: QUARKUS_OIDC_LOGOUT_PATH

string

 

quarkus.oidc.logout.post-logout-path

从 OpenID Connect 提供程序注销后,用户应重定向到的应用程序端点的相对路径。此端点 URI 必须在 OpenID Connect Provider 上正确注册,作为有效的重定向 URI。

环境变量: QUARKUS_OIDC_LOGOUT_POST_LOGOUT_PATH

string

 

quarkus.oidc.logout.post-logout-uri-param

post logout URI 参数的名称,作为查询参数添加到 logout 重定向 URI。

环境变量: QUARKUS_OIDC_LOGOUT_POST_LOGOUT_URI_PARAM

string

post_logout_redirect_uri

quarkus.oidc.logout.backchannel.path

应用程序中 Back-Channel Logout 端点的相对路径。

环境变量: QUARKUS_OIDC_LOGOUT_BACKCHANNEL_PATH

string

 

quarkus.oidc.logout.backchannel.token-cache-size

在与会话 Cookie 中存储的 ID 令牌匹配之前可以缓存的最大注销令牌数。

环境变量: QUARKUS_OIDC_LOGOUT_BACKCHANNEL_TOKEN_CACHE_SIZE

int

10

quarkus.oidc.logout.backchannel.token-cache-time-to-live

可以缓存注销令牌的分钟数。

环境变量: QUARKUS_OIDC_LOGOUT_BACKCHANNEL_TOKEN_CACHE_TIME_TO_LIVE

duration question circle

10M

quarkus.oidc.logout.backchannel.clean-up-timer-interval

令牌缓存计时器间隔。如果设置了此属性,则计时器会定期检查并删除过时的条目。

环境变量: QUARKUS_OIDC_LOGOUT_BACKCHANNEL_CLEAN_UP_TIMER_INTERVAL

duration question circle

 

quarkus.oidc.logout.backchannel.logout-token-key

注销令牌声明,其值用作缓存令牌的密钥。只有 sub (subject)和 sid (会话 ID)声明才能用作密钥。只有在 OIDC 供应商发布的 ID 令牌没有 但具有 sid 声明时,才会将其设置为 sid

环境变量: QUARKUS_OIDC_LOGOUT_BACKCHANNEL_LOGOUT_TOKEN_KEY

string

sub

quarkus.oidc.logout.frontchannel.path

应用程序中 Front-Channel Logout 端点的相对路径。

环境变量: QUARKUS_OIDC_LOGOUT_FRONTCHANNEL_PATH

string

 

quarkus.oidc.certificate-chain.leaf-certificate-name

leaf 证书的通用名称。如果 trust-store-file 没有导入此证书,则必须设置它。

环境变量: QUARKUS_OIDC_CERTIFICATE_CHAIN_LEAF_CERTIFICATE_NAME

string

 

quarkus.oidc.certificate-chain.trust-store-file

truststore 文件,用于保留可信证书的指纹。

环境变量: QUARKUS_OIDC_CERTIFICATE_CHAIN_TRUST_STORE_FILE

path

 

quarkus.oidc.certificate-chain.trust-store-password

如果使用 trust-store-file 配置,用于指定 truststore 文件的密码的参数。

环境变量: QUARKUS_OIDC_CERTIFICATE_CHAIN_TRUST_STORE_PASSWORD

string

 

quarkus.oidc.certificate-chain.trust-store-cert-alias

指定信任存储证书的别名的参数。

环境变量: QUARKUS_OIDC_CERTIFICATE_CHAIN_TRUST_STORE_CERT_ALIAS

string

 

quarkus.oidc.certificate-chain.trust-store-file-type

指定信任存储文件类型的可选参数。如果未指定,则根据文件名自动检测到类型。

环境变量: QUARKUS_OIDC_CERTIFICATE_CHAIN_TRUST_STORE_FILE_TYPE

string

 

quarkus.oidc.authentication.response-mode

授权代码流响应模式。

环境变量: QUARKUS_OIDC_AUTHENTICATION_RESPONSE_MODE

工具提示:query[Authorization 响应参数以添加到 redirect_uri] 的查询字符串中编码,即工具提示:form-post[Authorization 响应参数被编码为在浏览器中自动提交的 HTML 表单值,由 HTTP POST 方法传输,使用 application/x-www-form-urlencoded 内容类型]

query

quarkus.oidc.authentication.redirect-path

计算 redirect_uri 查询参数的相对路径。它必须从正斜杠开始,并附加到请求 URI 的主机和端口。例如,如果当前请求 URI 是 https://localhost:8080/service,如果此属性设置为 /,则 redirect_uri 参数被设置为 https://localhost:8080/,如果没有配置此属性,则与请求 URI 相同。请注意,如果 restorePathAfterRedirect 设为 true,则在用户通过身份验证后恢复原始请求 URI。

环境变量: QUARKUS_OIDC_AUTHENTICATION_REDIRECT_PATH

string

 

quarkus.oidc.authentication.restore-path-after-redirect

如果此属性设为 true,则在用户重定向到应用程序时恢复身份验证之前使用的原始请求 URI。请注意,如果没有设置 redirectPath 属性,则即使禁用了此属性,也会恢复原始请求 URI。

环境变量: QUARKUS_OIDC_AUTHENTICATION_RESTORE_PATH_AFTER_REDIRECT

布尔值

false

quarkus.oidc.authentication.remove-redirect-parameters

在用户通过将用户重定向到同一 URI 后,在重定向 URI 上删除由 OIDC 服务器设置 的代码和 状态,但没有查询参数。

环境变量: QUARKUS_OIDC_AUTHENTICATION_REMOVE_REDIRECT_PARAMETERS

布尔值

true

quarkus.oidc.authentication.error-path

指向处理 OIDC 授权端点错误响应的公共端点的相对路径。如果用户身份验证失败,OIDC 供应商会返回一个错误和可选的 error _description 参数,而不是预期的 授权代码。如果设置了此属性,用户会被重定向到端点,这可以返回用户友好的错误描述页面。它必须从正斜杠开始,并附加到请求 URI 的主机和端口。例如,如果它被设置为 /error,且当前请求 URI 为 https://localhost:8080/callback?error=invalid_scope,则会将重定向设置为 https://localhost:8080/error?error=invalid_scope。如果没有设置此属性,则在用户身份验证失败时会返回 HTTP 401 状态。

环境变量: QUARKUS_OIDC_AUTHENTICATION_ERROR_PATH

string

 

quarkus.oidc.authentication.verify-access-token

作为授权代码流的一部分,从 OIDC 供应商获取 ID 和访问令牌。ID 令牌始终在每个用户请求上验证,作为主令牌,用于代表主体并提取角色。默认情况下,不会验证访问令牌,因为它旨在传播到下游服务。如果访问令牌被注入为 JWT 令牌,则应启用访问令牌验证。如果 quarkus.oidc.roles.source 属性设置为 accesstoken,则始终验证作为代码流的一部分获取的访问令牌,这意味着授权决定基于从访问令牌中提取的角色。bearer 访问令牌总是被验证。

环境变量: QUARKUS_OIDC_AUTHENTICATION_VERIFY_ACCESS_TOKEN

布尔值

false

quarkus.oidc.authentication.force-redirect-https-scheme

在 SSL/TLS 终止反向代理后面运行时,强制 https 作为 redirect_uri 参数方案。如果启用,此属性也会影响 logout post_logout_redirect_uri 和本地重定向请求。

环境变量: QUARKUS_OIDC_AUTHENTICATION_FORCE_REDIRECT_HTTPS_SCHEME

布尔值

false

quarkus.oidc.authentication.scopes

范围列表

环境变量: QUARKUS_OIDC_AUTHENTICATION_SCOPES

字符串列表

 

quarkus.oidc.authentication.nonce-required

要求 ID 令牌包含非 ce 声明,该声明必须与 身份验证请求查询参数匹配。启用此属性可帮助缓解重播攻击。如果您的 OpenId Connect 供应商不支持在 ID 令牌中设置 非ce,或者与 OAuth2 供应商(如没有提供 ID 令牌的 GitHub )搭配使用,则不要启用此属性。

环境变量: QUARKUS_OIDC_AUTHENTICATION_NONCE_REQUIRED

布尔值

false

quarkus.oidc.authentication.add-openid-scope

openid 范围自动添加到范围列表中。这是 OpenId Connect 供应商所必需的,但不适用于 OAuth2 供应商,如 thread OAuth2,不接受此范围并抛出错误。

环境变量: QUARKUS_OIDC_AUTHENTICATION_ADD_OPENID_SCOPE

布尔值

true

quarkus.oidc.authentication.forward-params

请求 URL 查询参数(如果存在)添加到身份验证重定向 URI 中。

环境变量: QUARKUS_OIDC_AUTHENTICATION_FORWARD_PARAMS

字符串列表

 

quarkus.oidc.authentication.cookie-force-secure

如果启用了 state、session 和 post logout cookies,则在使用 HTTP 时将其 secure 参数设置为 true。在 SSL/TLS 终止反向代理后面运行时,可能需要这样做。如果使用 HTTPS,则 Cookie 始终安全,即使此属性设置为 false。

环境变量: QUARKUS_OIDC_AUTHENTICATION_COOKIE_FORCE_SECURE

布尔值

false

quarkus.oidc.authentication.cookie-suffix

Cookie 名称后缀。例如,默认 OIDC 租户的会话 Cookie 名称为 q_session,但如果此属性设置为 test,则可以更改为 q_session_test

环境变量: QUARKUS_OIDC_AUTHENTICATION_COOKIE_SUFFIX

string

 

quarkus.oidc.authentication.cookie-path

Cookie path 参数值(如果设置了)用于为会话设置 path 参数,state 和 post logout cookies。如果设置,则 Cookie-path-header 属性会首先检查。

环境变量: QUARKUS_OIDC_AUTHENTICATION_COOKIE_PATH

string

/

quarkus.oidc.authentication.cookie-path-header

Cookie path header 参数值(如果设置)标识传入的 HTTP 标头,其值用于为会话、状态和发布 logout cookie 设置 path 参数。如果缺少标头,则会检查 cookie-path 属性。

环境变量: QUARKUS_OIDC_AUTHENTICATION_COOKIE_PATH_HEADER

string

 

quarkus.oidc.authentication.cookie-domain

Cookie 域参数值(如果设置了)用于会话,state 和 post logout cookies。

环境变量: QUARKUS_OIDC_AUTHENTICATION_COOKIE_DOMAIN

string

 

quarkus.oidc.authentication.cookie-same-site

会话 Cookie 的 SameSite 属性。

环境变量: QUARKUS_OIDC_AUTHENTICATION_COOKIE_SAME_SITE

strict,lax,none

lax

quarkus.oidc.authentication.allow-multiple-code-flows

如果存在状态 Cookie,则 状态 查询参数也必须存在,并且当重定向路径与当前路径匹配时,状态 Cookie 名称后缀和状态 Cookie 值必须与状态 查询参数的值匹配。但是,如果从同一浏览器中尝试多个身份验证,例如从不同的浏览器标签页中,则当前可用的状态 cookie 可能代表从另一个标签页启动的身份验证流,而不是与当前请求相关的。禁用此属性,以在同一浏览器中只允许单个授权代码流。

环境变量: QUARKUS_OIDC_AUTHENTICATION_ALLOW_MULTIPLE_CODE_FLOWS

布尔值

true

quarkus.oidc.authentication.fail-on-missing-state-param

如果 state cookie 存在但没有状态查询参数,则失败并显示 HTTP 401 错误。

当禁用多个身份验证或者重定向 URL 与原始请求 URL 匹配时,过时的状态 Cookie 可能会保留在之前失败的浏览器缓存中,并可在当前请求中可见。例如,如果 Single-page 应用(SPA)使用 XHR 处理重定向到不支持其授权端点的 CORS 的提供程序,浏览器会阻止它,并且 Quarkus 创建的状态 Cookie 保留在浏览器缓存中。当检测到旧的状态 cookie 时,quarkus 会报告身份验证失败,但找不到匹配的状态查询参数。

报告 HTTP 401 错误通常是在这种情况下执行的正确操作,它会最小化浏览器重定向循环的风险,但还可以 SPA 或 Quarkus 应用程序管理重定向方式识别问题。例如,可能需要启用 java-script-auto-redirect,或者将供应商重定向到配置了 redirect-path 的 URL,以避免此类错误。

但是,如果上述选项不合适,则将此属性设置为 false 可以帮助。这会导致新的身份验证重定向到 OpenId Connect 供应商。这样做可能会增加浏览器重定向循环的风险。

环境变量: QUARKUS_OIDC_AUTHENTICATION_FAIL_ON_MISSING_STATE_PARAM

布尔值

false

quarkus.oidc.authentication.user-info-required

如果此属性设为 true,则调用 OIDC UserInfo 端点。如果 quarkus.oidc.roles.sourceuserinfo. 或 quarkus.oidc.token.verify-access-token-with-user-infotruequarkus.oidc.authentication.id-token-required 被设置为 false,则启用此属性。

环境变量: QUARKUS_OIDC_AUTHENTICATION_USER_INFO_REQUIRED

布尔值

false

quarkus.oidc.authentication.session-age-extension

会话期限扩展(以分钟为单位)。默认情况下,用户会话年龄属性被设置为 ID 令牌生命周期的值,用户会被重定向到 OIDC 供应商,以在会话过期后重新验证。如果此属性设置为非零值,则在会话过期前可以刷新过期的 ID 令牌。如果没有启用 token.refresh-expired 属性,则此属性会被忽略。

环境变量: QUARKUS_OIDC_AUTHENTICATION_SESSION_AGE_EXTENSION

duration question circle

5M

quarkus.oidc.authentication.java-script-auto-redirect

如果此属性设为 true,则返回普通的 302 重定向响应,如果请求是由 JavaScript API (如 XMLHttpRequest 或 Fetch)启动,且当前用户需要(re) authenticated,这可能不适用于单页应用程序(SPA),因为它自动遵循该 OIDC 授权端点通常不支持 CORS。

如果此属性设为 false,则返回 499 状态代码,以允许 SPA 在找到以 JavaScript 请求身份识别当前请求的请求标头时手动处理重定向。如果启用此属性,则默认预期 X-Requested-With 请求标头,其值设为 JavaScriptXMLHttpRequest。您可以注册自定义 JavaScriptRequestChecker 来执行自定义 JavaScript 请求检查。

环境变量: QUARKUS_OIDC_AUTHENTICATION_JAVA_SCRIPT_AUTO_REDIRECT

布尔值

true

quarkus.oidc.authentication.id-token-required

当授权代码流完成后,要求 ID 令牌可用。仅在您需要将授权代码流与 OAuth2 供应商(没有返回 ID 令牌)搭配使用时禁用此属性 - 在这种情况下会生成内部 IdToken。

环境变量: QUARKUS_OIDC_AUTHENTICATION_ID_TOKEN_REQUIRED

布尔值

true

quarkus.oidc.authentication.internal-id-token-lifespan

内部 ID 令牌寿命.只有在 Oauth2 供应商没有返回 IdToken 时,才会检查此属性。

环境变量: QUARKUS_OIDC_AUTHENTICATION_INTERNAL_ID_TOKEN_LIFESPAN

duration question circle

5M

quarkus.oidc.authentication.pkce-required

要求使用代码交换证明密钥(PKCE)。

环境变量: QUARKUS_OIDC_AUTHENTICATION_PKCE_REQUIRED

布尔值

false

quarkus.oidc.authentication.state-secret

用于为代码交换(PKCE)代码验证器(PKCE)代码验证器和/或非代码流状态加密概念验证的 secret。此 secret 应该至少为 32 个字符。

如果没有设置此 secret,则会检查使用 quarkus.oidc.credentials.secretquarkus.oidc.credentials.client-secret.value 配置的客户端 secret。最后,检查可用于 client_ jwt_secret 身份验证的 quarkus.oidc.credentials.jwt.secret。如果客户端 secret 小于 32 个字符,则不会将客户端 secret 用作状态加密 secret。

如果在检查所有这些属性后仍然未初始化,则自动生成该 secret。

如果 secret 长度小于 16 个字符,则报告错误。

环境变量: QUARKUS_OIDC_AUTHENTICATION_STATE_SECRET

string

 

quarkus.oidc.token-state-manager.strategy

默认 TokenStateManager 策略。

环境变量: QUARKUS_OIDC_TOKEN_STATE_MANAGER_STRATEGY

工具提示:keep-all-tokens[Keep ID, access and refresh token.], tooltip:id-token[Keep ID token only], tooltip:id-refresh-tokens[Keep ID and refresh token only]

keep-all-tokens

quarkus.oidc.token-state-manager.split-tokens

默认 TokenStateManager 会保留在授权代码中返回的所有令牌(ID、访问和刷新)默认授予单个会话 Cookie 的响应。启用此属性最小化会话 Cookie 大小

环境变量: QUARKUS_OIDC_TOKEN_STATE_MANAGER_SPLIT_TOKENS

布尔值

false

quarkus.oidc.token-state-manager.encryption-required

强制 Default TokenStateManager 加密存储令牌的会话 Cookie。

环境变量: QUARKUS_OIDC_TOKEN_STATE_MANAGER_ENCRYPTION_REQUIRED

布尔值

true

quarkus.oidc.token-state-manager.encryption-secret

Default TokenStateManager 用来加密在启用 encryption-required 属性时存储令牌的会话 Cookie 的 secret。

如果没有设置此 secret,则会检查使用 quarkus.oidc.credentials.secretquarkus.oidc.credentials.client-secret.value 配置的客户端 secret。最后,检查可用于 client_ jwt_secret 身份验证的 quarkus.oidc.credentials.jwt.secret。如果在检查所有这些属性后仍然未初始化,则自动生成该 secret。

用于加密令牌的 secret 的长度应至少为 32 个字符。如果 secret 长度小于 16 个字符,则会记录警告信息。

环境变量: QUARKUS_OIDC_TOKEN_STATE_MANAGER_ENCRYPTION_SECRET

string

 

quarkus.oidc.allow-token-introspection-cache

允许缓存令牌内省数据。请注意,启用此属性不启用缓存本身,但仅允许缓存给定租户的令牌内省。如果可以使用默认令牌缓存,请参阅 OidcConfig.TokenCache 来启用它。

环境变量: QUARKUS_OIDC_ALLOW_TOKEN_INTROSPECTION_CACHE

布尔值

true

quarkus.oidc.allow-user-info-cache

允许缓存用户信息数据。请注意,启用此属性不启用缓存本身,但只允许缓存给定租户的用户信息数据。如果可以使用默认令牌缓存,请参阅 OidcConfig.TokenCache 来启用它。

环境变量: QUARKUS_OIDC_ALLOW_USER_INFO_CACHE

布尔值

true

quarkus.oidc.cache-user-info-in-idtoken

允许在 IdToken 中简化 UserInfo,而不是将其缓存在令牌缓存中。只有在 Oauth2 供应商没有返回 IdToken 时,才会检查此属性。在生成的 IdToken 中,Inlining UserInfo 允许将其存储在会话 Cookie 中,并避免引入缓存的状态。

环境变量: QUARKUS_OIDC_CACHE_USER_INFO_IN_IDTOKEN

布尔值

false

quarkus.oidc.jwks.resolve-early

如果在连接到 OIDC 供应商时,应该获取 JWK 验证密钥。

禁用此属性会延迟密钥获取,直到必须验证当前令牌的时间。通常,只有在令牌或其他 telated 请求属性提供正确解析密钥所需的额外上下文时,才能需要它。

环境变量: QUARKUS_OIDC_JWKS_RESOLVE_EARLY

布尔值

true

quarkus.oidc.jwks.cache-size

可以缓存的最大 JWK 密钥数。如果 resolve-early 属性设为 true,则此属性会被忽略。

环境变量: QUARKUS_OIDC_JWKS_CACHE_SIZE

int

10

quarkus.oidc.jwks.cache-time-to-live

可以缓存 JWK 密钥的分钟数。如果 resolve-early 属性设为 true,则此属性会被忽略。

环境变量: QUARKUS_OIDC_JWKS_CACHE_TIME_TO_LIVE

duration question circle

10M

quarkus.oidc.jwks.clean-up-timer-interval

缓存计时器间隔。如果设置了此属性,则计时器会定期检查并删除过时的条目。如果 resolve-early 属性设为 true,则此属性会被忽略。

环境变量: QUARKUS_OIDC_JWKS_CLEAN_UP_TIMER_INTERVAL

duration question circle

 

quarkus.oidc.provider

已知的 OpenId Connect 供应商标识符

环境变量: QUARKUS_OIDC_PROVIDER

Apple,discord,facebook,github,google,linkedin,mas libpmemn,microsoft,spotify,strava,twitch,twitter,x

 

quarkus.oidc.token-cache.max-size

最大缓存条目数。如果需要启用缓存,则将其设置为正值。

环境变量: QUARKUS_OIDC_TOKEN_CACHE_MAX_SIZE

int

0

quarkus.oidc.token-cache.time-to-live

给定缓存条目有效的最大时间量。

环境变量: QUARKUS_OIDC_TOKEN_CACHE_TIME_TO_LIVE

duration question circle

3M

quarkus.oidc.token-cache.clean-up-timer-interval

清理计时器间隔。如果设置了此属性,则计时器将定期检查并删除过时的条目。

环境变量: QUARKUS_OIDC_TOKEN_CACHE_CLEAN_UP_TIMER_INTERVAL

duration question circle

 

lock quarkus.oidc.devui.grant-options

授权选项

环境变量: QUARKUS_OIDC_DEVUI_GRANT_OPTIONS

Map<String,Map<String,String>>

 

quarkus.oidc.credentials.jwt.claims

其他声明.

环境变量: QUARKUS_OIDC_CREDENTIALS_JWT_CLAIMS

Map<String,String>

 

quarkus.oidc.token.required-claims

所需的声明及其预期值的映射。例如,quarkus.oidc.token.required-claims.org_id = org_xyz 将要求令牌存在,并将 org_id 声明设置为 org_xyz。字符串是唯一支持的类型。使用 SecurityIdentityAugmentor 验证其他类型的或复杂声明的声明。

环境变量: QUARKUS_OIDC_TOKEN_REQUIRED_CLAIMS

Map<String,String>

 

quarkus.oidc.logout.extra-params

添加作为查询参数到 logout 重定向 URI 的额外属性。

环境变量: QUARKUS_OIDC_LOGOUT_EXTRA_PARAMS

Map<String,String>

 

quarkus.oidc.authentication.extra-params

添加作为查询参数到身份验证重定向 URI 的额外属性。

环境变量: QUARKUS_OIDC_AUTHENTICATION_EXTRA_PARAMS

Map<String,String>

 

quarkus.oidc.code-grant.extra-params

除了所需的 代码和 redirect-uri 参数外,还必须包含其他参数,才能完成授权代码授权请求。

环境变量: QUARKUS_OIDC_CODE_GRANT_EXTRA_PARAMS

Map<String,String>

 

quarkus.oidc.code-grant.headers

必须发送自定义 HTTP 标头来完成授权代码授权请求。

环境变量: QUARKUS_OIDC_CODE_GRANT_HEADERS

Map<String,String>

 

Additional named tenant

类型

default

quarkus.oidc."tenant".auth-server-url

OpenID Connect (OIDC)服务器的基本 URL,例如 https://host:port/auth。如果需要公钥验证(公钥)或仅需要证书链验证(certificate-chain),则不要设置此属性。默认情况下,OIDC 发现端点会在这个 URL 中附加 .well-known/openid-configuration 路径来调用。对于 Keycloak,使用 https://host:port/realms/{realm},将 {realm} 替换为 Keycloak 域名。

环境变量: QUARKUS_OIDC__TENANT__AUTH_SERVER_URL

string

 

quarkus.oidc."tenant".discovery-enabled

发现 OIDC 端点。如果没有启用,您必须单独配置 OIDC 端点 URL。

环境变量: QUARKUS_OIDC__TENANT__DISCOVERY_ENABLED

布尔值

true

quarkus.oidc."tenant".token-path

签发访问和刷新令牌的 OIDC 令牌端点;指定为相对路径或绝对 URL。如果 discovery-enabledfalse,或必须自定义发现的令牌端点路径。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_PATH

string

 

quarkus.oidc."tenant".revoke-path

OIDC 令牌撤销端点的相对路径或绝对路径 URL。

环境变量: QUARKUS_OIDC__TENANT__REVOKE_PATH

string

 

quarkus.oidc."tenant".client-id

应用程序的客户端 ID。每个应用都有一个客户端 ID,用于标识应用程序。如果 application-typeservice,且不需要令牌内省,则不需要设置客户端 ID。

环境变量: QUARKUS_OIDC__TENANT__CLIENT_ID

string

 

quarkus.oidc."tenant".connection-delay

尝试初始连接到 OIDC 服务器的持续时间。例如,将持续时间设置为 20S 允许 10 次重试,每 2 秒。此属性仅在创建初始 OIDC 连接时才有效。对于丢弃的连接,请使用 connection-retry-count 属性。

环境变量: QUARKUS_OIDC__TENANT__CONNECTION_DELAY

duration question circle

 

quarkus.oidc."tenant".connection-retry-count

如果临时丢失,重试重新建立现有 OIDC 连接的次数。与 connection-delay 不同,它只适用于初始连接尝试。例如,如果对 OIDC 令牌端点的请求因为连接问题而失败,它将按此设置重试。

环境变量: QUARKUS_OIDC__TENANT__CONNECTION_RETRY_COUNT

int

3

quarkus.oidc."tenant".connection-timeout

当前 OIDC 连接请求超时的秒数。

环境变量: QUARKUS_OIDC__TENANT__CONNECTION_TIMEOUT

duration question circle

10S

quarkus.oidc."tenant".use-blocking-dns-lookup

是否应该在 worker 线程上执行 DNS 查找。当您可以参阅 HTTP 请求到 OIDC 服务器来记录有关阻止的 Vert.x 事件循环的日志记录警告时,请使用这个选项。

环境变量: QUARKUS_OIDC__TENANT__USE_BLOCKING_DNS_LOOKUP

布尔值

false

quarkus.oidc."tenant".max-pool-size

WebClient 使用的连接池的最大大小。

环境变量: QUARKUS_OIDC__TENANT__MAX_POOL_SIZE

int

 

quarkus.oidc."tenant".credentials.secret

client_secret_basic 身份验证方法使用的客户端 secret。必须设置,除非需要在 client-secretjwt 客户端身份验证中设置 secret。您可以使用 client-secret.value,但这两个属性都是互斥的。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_SECRET

string

 

quarkus.oidc."tenant".credentials.client-secret.value

客户端机密值。如果设置了 credentials.secret,则忽略这个值。必须设置,除非需要在 client-secretjwt 客户端身份验证中设置 secret。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_CLIENT_SECRET_VALUE

string

 

quarkus.oidc."tenant".credentials.client-secret.provider.name

CredentialsProvider 名称,只有在注册了多个 CredentialsProvider 时才应设置

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_CLIENT_SECRET_PROVIDER_NAME

string

 

quarkus.oidc."tenant".credentials.client-secret.provider.key

CredentialsProvider 客户端 secret 密钥

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_CLIENT_SECRET_PROVIDER_KEY

string

 

quarkus.oidc."tenant".credentials.client-secret.method

身份验证方法。如果设置了 clientSecret.value secret,则此方法默认是 基本的

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_CLIENT_SECRET_METHOD

工具提示:basic[client_secret_basic (默认): 客户端 ID 和 secret 使用 HTTP 授权基本方案提交。],工具提示:post[ client_secret_ post : 客户端 ID 和 secret 作为 client _ id 和 client _secret 表单参数提交。],工具提示:post-jwt[ client_secret _jwt : 客户端 ID 和生成的 JWT secret 作为 client _id 和 client_secret 表格参数提交。],工具提示:query[client id 和 secret 作为 HTTP 查询参数提交。这个选项只支持 OIDC 扩展。]

 

quarkus.oidc."tenant".credentials.jwt.secret

如果提供,则表示 JWT 使用 secret 密钥进行了签名。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_SECRET

string

 

quarkus.oidc."tenant".credentials.jwt.secret-provider.name

CredentialsProvider 名称,只有在注册了多个 CredentialsProvider 时才应设置

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_SECRET_PROVIDER_NAME

string

 

quarkus.oidc."tenant".credentials.secret-provider.key

CredentialsProvider 客户端 secret 密钥

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_SECRET_PROVIDER_KEY

string

 

quarkus.oidc."tenant".credentials.jwt.key-file

如果提供,则表示 JWT 是使用 PEM 或 JWK 格式的私钥签名的。您可以使用 signature-algorithm 属性覆盖默认的密钥算法 RS256

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_KEY_FILE

string

 

quarkus.oidc."tenant".credentials.jwt.key-store-file

如果提供,则表示 JWT 使用密钥存储中的私钥签名。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_KEY_STORE_FILE

string

 

quarkus.oidc."tenant".credentials.key-store-password

指定密钥存储文件的密码的参数。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_KEY_STORE_PASSWORD

string

 

quarkus.oidc."tenant".credentials.jwt.key-id

私钥 ID 或别名。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_KEY_ID

string

 

quarkus.oidc."tenant".credentials.jwt.key-password

私钥密码。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_KEY_PASSWORD

string

 

quarkus.oidc."tenant".credentials.jwt.audience

JWT 受众(ud)声明值。默认情况下,audience 设置为 OpenId Connect Provider 的令牌端点的地址。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_AUDIENCE

string

 

quarkus.oidc."tenant".credentials.jwt.token-key-id

添加为 JWT kid 标头的签名密钥标识符。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_TOKEN_KEY_ID

string

 

quarkus.oidc."tenant".credentials.jwt.issuer

添加为 JWT 的签名密钥的签发者 是s 声明。默认值为客户端 ID。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_ISSUER

string

 

quarkus.oidc."tenant".credentials.jwt.subject

添加为 JWT 声明的签名密钥的主题。默认值是客户端 ID。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_SUBJECT

string

 

quarkus.oidc."tenant".credentials.jwt.claims

其他声明.

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_CLAIMS

Map<String,String>

 

quarkus.oidc."tenant".credentials.jwt.signature-algorithm

用于 key-file 属性的签名算法。支持的值有: RS256 (默认)、RS384RS512PS256PS384PS512、ES256、ES256ES384、ES512、ES512、ES512、ESS256HS384HS512.

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_SIGNATURE_ALGORITHM

string

 

quarkus.oidc."tenant".credentials.jwt.lifespan

JWT 生命周期(以秒为单位)。这个值添加到发出 JWT 的时间,以计算过期时间。

环境变量: QUARKUS_OIDC__TENANT__CREDENTIALS_JWT_LIFESPAN

int

10

quarkus.oidc."tenant".proxy.host

代理的主机名或 IP 地址。
注: 如果 OIDC 适配器需要代理与 OIDC 服务器(Provider)通信,请将此值设置为以启用代理的使用。

环境变量: QUARKUS_OIDC__TENANT__PROXY_HOST

string

 

quarkus.oidc."tenant".proxy.port

代理的端口号。默认值为 80

环境变量: QUARKUS_OIDC__TENANT__PROXY_PORT

int

80

quarkus.oidc."tenant".proxy.username

如果代理需要身份验证,则用户名。

环境变量: QUARKUS_OIDC__TENANT_PROXY_USERNAME

string

 

quarkus.oidc."tenant".proxy.password

如果代理需要身份验证,则密码。

环境变量: QUARKUS_OIDC__TENANT__PROXY_PASSWORD

string

 

quarkus.oidc."tenant".tls.verification

证书验证和主机名验证,可以是以下 验证值之一。默认为

环境变量: QUARKUS_OIDC__TENANT__TLS_VERIFICATION

工具提示:required[Certificates 被验证,并且启用了主机名验证。这是默认的 value.],工具提示:certificate-validation[Certificates 被验证,但主机名验证为 disabled.],提示提示:none[All 证书是可信的,主机名验证被禁用。]

 

quarkus.oidc."tenant".tls.key-store-file

保存证书信息的可选密钥存储,而不是指定单独的文件。

环境变量: QUARKUS_OIDC__TENANT__TLS_KEY_STORE_FILE

path

 

quarkus.oidc."tenant".tls.key-store-file-type

密钥存储文件的类型。如果未指定,则根据文件名自动检测到类型。

环境变量: QUARKUS_OIDC__TENANT__TLS_KEY_STORE_FILE_TYPE

string

 

quarkus.oidc."tenant".tls.key-store-provider

密钥存储文件的提供程序。如果未指定,则根据密钥存储文件类型自动检测到该提供程序。

环境变量: QUARKUS_OIDC__TENANT__TLS_KEY_STORE_PROVIDER

string

 

quarkus.oidc."tenant".tls.key-store-password

密钥存储文件的密码。如果未指定,则使用默认值,即 密码

环境变量: QUARKUS_OIDC__TENANT__TLS_KEY_STORE_PASSWORD

string

 

quarkus.oidc."tenant".tls.key-store-key-alias

密钥存储中特定密钥的别名。禁用 SNI 时,如果密钥存储包含多个密钥且没有指定别名,则行为未定义。

环境变量: QUARKUS_OIDC__TENANT__TLS_KEY_STORE_KEY_ALIAS

string

 

quarkus.oidc."tenant".tls.key-store-key-password

密钥的密码(如果与 key-store-password 不同)。

环境变量: QUARKUS_OIDC__TENANT__TLS_KEY_STORE_KEY_PASSWORD

string

 

quarkus.oidc."tenant".tls.trust-store-file

保存要信任的证书信息的信任存储。

环境变量: QUARKUS_OIDC__TENANT__TLS_TRUST_STORE_FILE

path

 

quarkus.oidc."tenant".tls.trust-store-password

truststore 文件的密码。

环境变量: QUARKUS_OIDC__TENANT__TLS_TRUST_STORE_PASSWORD

string

 

quarkus.oidc."tenant".tls.trust-store-cert-alias

信任存储证书的别名。

环境变量: QUARKUS_OIDC__TENANT__TLS_TRUST_STORE_CERT_ALIAS

string

 

quarkus.oidc."tenant".tls.trust-store-file-type

truststore 文件的类型。如果未指定,则根据文件名自动检测到类型。

环境变量: QUARKUS_OIDC__TENANT__TLS_TRUST_STORE_FILE_TYPE

string

 

quarkus.oidc."tenant".tls.trust-store-provider

truststore 文件的供应商。如果没有提供,则会根据信任存储文件类型自动检测到供应商。

环境变量: QUARKUS_OIDC__TENANT__TLS_TRUST_STORE_PROVIDER

string

 

quarkus.oidc."tenant".tenant-id

唯一的租户标识符。它可以由 TenantConfigResolver 提供程序设置,后者可以动态解析租户配置。

环境变量: QUARKUS_OIDC__TENANT__TENANT_ID

string

 

quarkus.oidc."tenant".tenant-enabled

如果启用了此租户配置。如果没有配置,但支持租户配置的 TenantConfigResolver,则默认租户会被禁用,或者配置了命名的租户。在这种情况下,您不需要禁用默认租户。

环境变量: QUARKUS_OIDC__TENANT__TENANT_ENABLED

布尔值

true

quarkus.oidc."tenant".application-type

应用程序类型,可以是以下 ApplicationType 值之一。

环境变量: QUARKUS_OIDC__TENANT__APPLICATION_TYPE

工具提示:web-app[A WEB_APP 是提供页面(通常是前端应用程序)的客户端。对于这种类型的客户端,Authorization Code Flow 定义为验证用户的首选方法。],工具提示:service[A SERVICE 是一个具有一组受保护的 HTTP 资源的客户端,通常是遵循 RESTful 架构师设计的后端服务。对于这种类型的客户端,Bearer Authorization 方法定义为身份验证和授权用户的首选方法。],工具提示:hybrid[A combined SERVICEWEB_APP 客户端。对于这种类型的客户端,如果设置了 Authorization 标头和 Authorization Code Flow - 如果不是,则使用 Bearer Authorization 方法。]

service

quarkus.oidc."tenant".authorization-path

OpenID Connect (OIDC)授权端点的相对路径或绝对 URL,用于验证用户。如果 OIDC 发现被禁用,则必须为 web-app 应用程序设置此属性。如果启用了 OIDC 发现,则忽略此属性。

环境变量: QUARKUS_OIDC__TENANT__AUTHORIZATION_PATH

string

 

quarkus.oidc."tenant".user-info-path

OIDC UserInfo 端点的相对路径或绝对路径 URL。如果 OIDC 发现被禁用并且启用了 authentication.user-info-required 属性,则必须为 web-app 应用程序设置此属性。如果启用了 OIDC 发现,则忽略此属性。

环境变量: QUARKUS_OIDC__TENANT__USER_INFO_PATH

string

 

quarkus.oidc."tenant".introspection-path

OIDC RFC7662 内省端点的相对路径或绝对路径 URL,这些端点可以内省不透明和 JSON Web 令牌(JWT)令牌。如果禁用了 OIDC 发现,并且必须验证不透明 bearer 访问令牌,或 2)当缓存的 JWK 验证集没有匹配的 JWK 验证集时,必须设置此属性。如果启用了发现,则忽略此属性。

环境变量: QUARKUS_OIDC__TENANT__INTROSPECTION_PATH

string

 

quarkus.oidc."tenant".jwks-path

返回 JSON Web 密钥验证集的 OIDC JSON Web Key Set (JWKS)端点的相对路径或绝对路径。如果禁用了 OIDC 发现且需要本地 JWT 验证,则应设置此属性。如果启用了发现,则忽略此属性。

环境变量: QUARKUS_OIDC__TENANT__JWKS_PATH

string

 

quarkus.oidc."tenant".end-session-path

OIDC end_session_endpoint 的相对路径或绝对路径 URL。如果禁用了 OIDC 发现,并且需要对 web-app 应用程序的 RP Initiated Logout 支持,则必须设置此属性。如果启用了发现,则忽略此属性。

环境变量: QUARKUS_OIDC__TENANT__END_SESSION_PATH

string

 

quarkus.oidc."tenant".public-key

本地 JWT 令牌验证的公钥。当设置此属性时,不会创建 OIDC 服务器连接。

环境变量: QUARKUS_OIDC__TENANT__PUBLIC_KEY

string

 

quarkus.oidc."tenant".introspection-credentials.name

Name

环境变量: QUARKUS_OIDC__TENANT__INTROSPECTION_CREDENTIALS_NAME

string

 

quarkus.oidc."tenant".introspection-credentials.secret

Secret

环境变量: QUARKUS_OIDC__TENANT__INTROSPECTION_CREDENTIALS_SECRET

string

 

quarkus.oidc."tenant".introspection-credentials.include-client-id

包含使用 quarkus.oidc.client-id 配置的 OpenId Connect Client ID。

环境变量: QUARKUS_OIDC__TENANT__INTROSPECTION_CREDENTIALS_INCLUDE_CLIENT_ID

布尔值

true

quarkus.oidc."tenant".roles.role-claim-path

包含组数组的声明的路径列表。每个路径从顶级 JWT JSON 对象开始,并可以包含多个片段。每个片段仅代表一个 JSON 对象名称,例如:"realm/groups"。使用带命名空间限定声明名称的双引号。如果令牌没有 声明,但有一个或多个不同声明中设置的组,则可以使用此属性。

环境变量: QUARKUS_OIDC__TENANT_ROLES_ROLE_CLAIM_PATH

字符串列表

 

quarkus.oidc."tenant".roles.role-claim-separator

包含多个组值的字符串的分隔符。只有在 "role-claim-path" 属性指向值为字符串的一个或多个自定义声明时才使用它。默认情况下会使用单个空格,因为标准 范围 声明可以包含空格分隔的序列。

环境变量: QUARKUS_OIDC__TENANT_ROLES_ROLE_CLAIM_SEPARATOR

string

 

quarkus.oidc."tenant".roles.source

主体角色的源。

环境变量: QUARKUS_OIDC__TENANT_ROLES_SOURCE

工具提示:idtoken[ID Token - web-app applications.], tooltip:accesstoken[Access Token - 服务 应用程序的默认值; 也可以用作 web-app application.], 工具提示:userinfo[User Info] 的角色源。

 

quarkus.oidc."tenant".token.issuer

预期的签发者 是声明 值。此属性覆盖 issuer 属性,它可能会在 OpenId Connect 供应商已知的配置中设置。如果 iss claim 值因提供程序的主机、IP 地址或租户 ID 不同,您可以通过将此属性设置为 任何 来跳过签发者验证,但应仅在其他选项(如配置提供程序使用固定声明值)时执行。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_ISSUER

string

 

quarkus.oidc."tenant".token.audience

预期 受众 的声明值,可以是字符串或字符串数组。请注意,默认情况下,验证了 audience 声明 ID 令牌。ID 令牌使用者必须等于 quarkus.oidc.client-id 属性的值。如果您的 OpenID Connect 供应商在 ID 令牌中设置不同的 audience 声明值,请使用此属性覆盖预期的值。如果您的供应商没有设置 ID 令牌使用者的声明,则将其设置为 任何。只有在配置了此属性时,才会对访问令牌进行使用者验证。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_AUDIENCE

字符串列表

 

quarkus.oidc."tenant".token.subject-required

要求令牌包含 sub (subject)声明,它是当前用户的唯一且永远不会重新分配的标识符。请注意,如果您启用此属性,并且还需要 UserInfo,则必须存在 token 和 UserInfo 声明,并相互匹配。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_SUBJECT_REQUIRED

布尔值

false

quarkus.oidc."tenant".token.required-claims

所需的声明及其预期值的映射。例如,quarkus.oidc.token.required-claims.org_id = org_xyz 将要求令牌存在,并将 org_id 声明设置为 org_xyz。字符串是唯一支持的类型。使用 SecurityIdentityAugmentor 验证其他类型的或复杂声明的声明。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_REQUIRED_CLAIMS

Map<String,String>

 

quarkus.oidc."tenant".token.token-type

预期的令牌类型

环境变量: QUARKUS_OIDC__TENANT_TOKEN_TOKEN_TYPE

string

 

quarkus.oidc."tenant".token.lifespan-grace

生命周期跨宽限期(以秒为单位)。在检查令牌到期时,允许当前的时间超过令牌过期时间(最多配置的秒数)。在检查令牌颁发时,当前时间最多允许于令牌问题时间超过配置的秒数。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_LIFESPAN_GRACE

int

 

quarkus.oidc."tenant".token.age

令牌期限.它可指定自 iat (在)时间后不得经过的秒数。一个小的用于时钟偏移的 leeway,它可以使用 quarkus.oidc.token.lifespan-grace 来配置,以验证令牌到期时间也可以用于验证令牌年龄属性。请注意,设置此属性不会放宽 Bearer 和代码流 JWT 令牌必须具有有效的(exp)到期声明值的要求。设置此属性放松需要的唯一例外是,当注销令牌与后端退出请求发送时,因为当前的 OpenId Connect Back-Channel 规格没有明确要求包含 exp 声明。但是,即使当前注销令牌没有 exp 声明,仍然会在注销令牌包含该令牌时验证 exp 声明。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_AGE

duration question circle

 

quarkus.oidc."tenant".token.principal-claim

包含主体名称的声明的名称。默认情况下,会检查 upnpreferred_usernamesub 声明。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_PRINCIPAL_CLAIM

string

 

quarkus.oidc."tenant".token.refresh-expired

刷新已过期的授权代码流 ID 或访问令牌。如果启用了此属性,如果授权代码 ID 或访问令牌已过期,则会执行刷新令牌请求,如果成功,本地会话会使用新的令牌集合更新。否则,本地会话将无效,用户重定向到 OpenID 提供程序以重新进行身份验证。在这种情况下,如果 OIDC 供应商会话仍然活跃,用户可能无法再次挑战。对于此选项,password _session-age-extension 属性也应设置为非零值,因为刷新令牌当前保留在用户会话中。只有在应用程序类型为 ApplicationType#WEB_APP} 时,这个选项才有效。如果配置了 quarkus.oidc.token.refresh-token-time-skew,则不需要在本例中手动启用此属性。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_REFRESH_EXPIRED

布尔值

false

quarkus.oidc."tenant".token.refresh-token-time-skew

刷新令牌时间偏移(以秒为单位)。如果启用了此属性,在检查授权代码 ID 或访问令牌是否应刷新时,配置的秒数会添加到当前时间。如果总和大于授权代码 ID 或访问令牌的过期时间,则会进行刷新。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_REFRESH_TOKEN_TIME_SKEW

duration question circle

 

quarkus.oidc."tenant".token.forced-jwk-refresh-interval

强制 JWK 设置刷新间隔(以分钟为单位)。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_FORCED_JWK_REFRESH_INTERVAL

duration question circle

10M

quarkus.oidc."tenant".token.header

包含 bearer 令牌的自定义 HTTP 标头。只有在应用程序类型为 ApplicationType CPUfreqSERVICE } 时,这个选项才有效。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_HEADER

string

 

quarkus.oidc."tenant".token.authorization-scheme

HTTP 授权标头方案.

环境变量: QUARKUS_OIDC__TENANT_TOKEN_AUTHORIZATION_SCHEME

string

bearer

quarkus.oidc."tenant".token.signature-algorithm

所需的签名算法。OIDC 供应商支持许多签名算法,但如果需要,您可以限制 Quarkus 应用程序来接受仅使用此属性配置的算法签名的令牌。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_SIGNATURE_ALGORITHM

rs256,rs 384,rs512,ps256,ps384,ps512,es256,es384,es512,edsa

 

quarkus.oidc."tenant".token.decryption-key-location

解密密钥位置.JWT 令牌可由 OpenId Connect 提供程序进行内部签名和加密。但是,并不总是能够远程内省此类令牌,因为提供程序可能无法控制私钥。在这种情况下,将此属性设置为指向包含 PEM 或 JSON Web 密钥(JWK)格式的解密私钥的文件。如果没有设置此属性,并且使用了 private_key_jwt 客户端身份验证方法,则用于为客户端身份验证 JWT 令牌签名的私钥也用于解密加密的 ID 令牌。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_DECRYPTION_KEY_LOCATION

string

 

quarkus.oidc."tenant".token.allow-jwt-introspection

当没有匹配的 JWK 密钥时,允许远程内省 JWT 令牌。出于向后兼容性的原因,此属性默认设置为 true。计划在以后的发行版本中,此默认值将更改为 false。另请注意,如果 JWK 端点 URI 不可用并且内省令牌是唯一验证选项,则此属性将被忽略。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_ALLOW_JWT_INTROSPECTION

布尔值

true

quarkus.oidc."tenant".token.require-jwt-introspection-only

要求仅远程内省 JWT 令牌。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_REQUIRE_JWT_INTROSPECTION_ONLY

布尔值

false

quarkus.oidc."tenant".token.allow-opaque-token-introspection

允许远程内省不透明令牌。如果只有 JWT 令牌,则将此属性设置为 false

环境变量: QUARKUS_OIDC__TENANT_TOKEN_ALLOW_OPAQUE_TOKEN_INTROSPECTION

布尔值

true

quarkus.oidc."tenant".token.customizer-name

令牌自定义器名称。允许选择特定于租户的令牌自定义器作为命名 Bean。在注册自定义令牌时,首选使用 Tenant Feature qualifier。使用此属性只引用此扩展提供的 TokenCustomizer 实现。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_CUSTOMIZER_NAME

string

 

quarkus.oidc."tenant".token.verify-access-token-with-user-info

间接验证不透明(二进制)访问令牌是否有效,方法是请求 UserInfo。如果提供商接受此令牌并返回有效的 UserInfo,则不透明访问令牌被视为有效。只有在必须接受不透明访问令牌但 OpenId Connect 供应商没有令牌内省端点时,才应启用此选项。当必须验证 JWT 令牌时,此属性无效。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_VERIFY_ACCESS_TOKEN_WITH_USER_INFO

布尔值

false

quarkus.oidc."tenant".logout.path

应用程序上 logout 端点的相对路径。如果提供,应用程序可以通过此端点启动注销,并符合 OpenID Connect RP-Initiated Logout 规格。

环境变量: QUARKUS_OIDC__TENANT__LOGOUT_PATH

string

 

quarkus.oidc."tenant".logout.post-logout-path

从 OpenID Connect 提供程序注销后,用户应重定向到的应用程序端点的相对路径。此端点 URI 必须在 OpenID Connect Provider 上正确注册,作为有效的重定向 URI。

环境变量: QUARKUS_OIDC__TENANT_LOGOUT_POST_LOGOUT_PATH

string

 

quarkus.oidc."tenant".logout.post-logout-uri-param

post logout URI 参数的名称,作为查询参数添加到 logout 重定向 URI。

环境变量: QUARKUS_OIDC__TENANT__LOGOUT_POST_LOGOUT_URI_PARAM

string

post_logout_redirect_uri

quarkus.oidc."tenant".logout.extra-params

添加作为查询参数到 logout 重定向 URI 的额外属性。

环境变量: QUARKUS_OIDC__TENANT_LOGOUT_EXTRA_PARAMS

Map<String,String>

 

quarkus.oidc."tenant".logout.backchannel.path

应用程序中 Back-Channel Logout 端点的相对路径。

环境变量: QUARKUS_OIDC__TENANT_LOGOUT_BACKCHANNEL_PATH

string

 

quarkus.oidc."tenant".logout.backchannel.token-cache-size

在与会话 Cookie 中存储的 ID 令牌匹配之前可以缓存的最大注销令牌数。

环境变量: QUARKUS_OIDC__TENANT_LOGOUT_BACKCHANNEL_TOKEN_CACHE_SIZE

int

10

quarkus.oidc."tenant".logout.backchannel.token-cache-time-to-live

可以缓存注销令牌的分钟数。

环境变量: QUARKUS_OIDC__TENANT_LOGOUT_BACKCHANNEL_TOKEN_CACHE_TIME_TO_LIVE

duration question circle

10M

quarkus.oidc."tenant".logout.backchannel.clean-up-timer-interval

令牌缓存计时器间隔。如果设置了此属性,则计时器会定期检查并删除过时的条目。

环境变量: QUARKUS_OIDC__TENANT_LOGOUT_BACKCHANNEL_CLEAN_UP_TIMER_INTERVAL

duration question circle

 

quarkus.oidc."tenant".logout.backchannel.logout-token-key

注销令牌声明,其值用作缓存令牌的密钥。只有 sub (subject)和 sid (会话 ID)声明才能用作密钥。只有在 OIDC 供应商发布的 ID 令牌没有 但具有 sid 声明时,才会将其设置为 sid

环境变量: QUARKUS_OIDC__TENANT_LOGOUT_BACKCHANNEL_LOGOUT_TOKEN_KEY

string

sub

quarkus.oidc."tenant".logout.frontchannel.path

应用程序中 Front-Channel Logout 端点的相对路径。

环境变量: QUARKUS_OIDC__TENANT_LOGOUT_FRONTCHANNEL_PATH

string

 

quarkus.oidc."tenant".certificate-chain.leaf-certificate-name

leaf 证书的通用名称。如果 trust-store-file 没有导入此证书,则必须设置它。

环境变量: QUARKUS_OIDC__TENANT__CERTIFICATE_CHAIN_LEAF_CERTIFICATE_NAME

string

 

quarkus.oidc."tenant".certificate-chain.trust-store-file

truststore 文件,用于保留可信证书的指纹。

环境变量: QUARKUS_OIDC__TENANT__CERTIFICATE_CHAIN_TRUST_STORE_FILE

path

 

quarkus.oidc."tenant".certificate-chain.trust-store-password

如果使用 trust-store-file 配置,用于指定 truststore 文件的密码的参数。

环境变量: QUARKUS_OIDC__TENANT__CERTIFICATE_CHAIN_TRUST_STORE_PASSWORD

string

 

quarkus.oidc."tenant".certificate-chain.trust-store-cert-alias

指定信任存储证书的别名的参数。

环境变量: QUARKUS_OIDC__TENANT__CERTIFICATE_CHAIN_TRUST_STORE_CERT_ALIAS

string

 

quarkus.oidc."tenant".certificate-chain.trust-store-file-type

指定信任存储文件类型的可选参数。如果未指定,则根据文件名自动检测到类型。

环境变量: QUARKUS_OIDC__TENANT__CERTIFICATE_CHAIN_TRUST_STORE_FILE_TYPE

string

 

quarkus.oidc."tenant".authentication.response-mode

授权代码流响应模式。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_RESPONSE_MODE

工具提示:query[Authorization 响应参数以添加到 redirect_uri] 的查询字符串中编码,即工具提示:form-post[Authorization 响应参数被编码为在浏览器中自动提交的 HTML 表单值,由 HTTP POST 方法传输,使用 application/x-www-form-urlencoded 内容类型]

query

quarkus.oidc."tenant".authentication.redirect-path

计算 redirect_uri 查询参数的相对路径。它必须从正斜杠开始,并附加到请求 URI 的主机和端口。例如,如果当前请求 URI 是 https://localhost:8080/service,如果此属性设置为 /,则 redirect_uri 参数被设置为 https://localhost:8080/,如果没有配置此属性,则与请求 URI 相同。请注意,如果 restorePathAfterRedirect 设为 true,则在用户通过身份验证后恢复原始请求 URI。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_REDIRECT_PATH

string

 

quarkus.oidc."tenant".authentication.restore-path-after-redirect

如果此属性设为 true,则在用户重定向到应用程序时恢复身份验证之前使用的原始请求 URI。请注意,如果没有设置 redirectPath 属性,则即使禁用了此属性,也会恢复原始请求 URI。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_RESTORE_PATH_AFTER_REDIRECT

布尔值

false

quarkus.oidc."tenant".authentication.remove-redirect-parameters

在用户通过将用户重定向到同一 URI 后,在重定向 URI 上删除由 OIDC 服务器设置 的代码和 状态,但没有查询参数。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_REMOVE_REDIRECT_PARAMETERS

布尔值

true

quarkus.oidc."tenant".authentication.error-path

指向处理 OIDC 授权端点错误响应的公共端点的相对路径。如果用户身份验证失败,OIDC 供应商会返回一个错误和可选的 error _description 参数,而不是预期的 授权代码。如果设置了此属性,用户会被重定向到端点,这可以返回用户友好的错误描述页面。它必须从正斜杠开始,并附加到请求 URI 的主机和端口。例如,如果它被设置为 /error,且当前请求 URI 为 https://localhost:8080/callback?error=invalid_scope,则会将重定向设置为 https://localhost:8080/error?error=invalid_scope。如果没有设置此属性,则在用户身份验证失败时会返回 HTTP 401 状态。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_ERROR_PATH

string

 

quarkus.oidc."tenant".authentication.verify-access-token

作为授权代码流的一部分,从 OIDC 供应商获取 ID 和访问令牌。ID 令牌始终在每个用户请求上验证,作为主令牌,用于代表主体并提取角色。默认情况下,不会验证访问令牌,因为它旨在传播到下游服务。如果访问令牌被注入为 JWT 令牌,则应启用访问令牌验证。如果 quarkus.oidc.roles.source 属性设置为 accesstoken,则始终验证作为代码流的一部分获取的访问令牌,这意味着授权决定基于从访问令牌中提取的角色。bearer 访问令牌总是被验证。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_VERIFY_ACCESS_TOKEN

布尔值

false

quarkus.oidc."tenant".authentication.force-redirect-https-scheme

在 SSL/TLS 终止反向代理后面运行时,强制 https 作为 redirect_uri 参数方案。如果启用,此属性也会影响 logout post_logout_redirect_uri 和本地重定向请求。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_FORCE_REDIRECT_HTTPS_SCHEME

布尔值

false

quarkus.oidc."tenant".authentication.scopes

范围列表

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_SCOPES

字符串列表

 

quarkus.oidc."tenant".authentication.nonce-required

要求 ID 令牌包含非 ce 声明,该声明必须与 身份验证请求查询参数匹配。启用此属性可帮助缓解重播攻击。如果您的 OpenId Connect 供应商不支持在 ID 令牌中设置 非ce,或者与 OAuth2 供应商(如没有提供 ID 令牌的 GitHub )搭配使用,则不要启用此属性。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_NONCE_REQUIRED

布尔值

false

quarkus.oidc."tenant".authentication.add-openid-scope

openid 范围自动添加到范围列表中。这是 OpenId Connect 供应商所必需的,但不适用于 OAuth2 供应商,如 thread OAuth2,不接受此范围并抛出错误。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_ADD_OPENID_SCOPE

布尔值

true

quarkus.oidc."tenant".authentication.extra-params

添加作为查询参数到身份验证重定向 URI 的额外属性。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_EXTRA_PARAMS

Map<String,String>

 

quarkus.oidc."tenant".authentication.forward-params

请求 URL 查询参数(如果存在)添加到身份验证重定向 URI 中。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_FORWARD_PARAMS

字符串列表

 

quarkus.oidc."tenant".authentication.cookie-force-secure

如果启用了 state、session 和 post logout cookies,则在使用 HTTP 时将其 secure 参数设置为 true。在 SSL/TLS 终止反向代理后面运行时,可能需要这样做。如果使用 HTTPS,则 Cookie 始终安全,即使此属性设置为 false。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_COOKIE_FORCE_SECURE

布尔值

false

quarkus.oidc."tenant".authentication.cookie-suffix

Cookie 名称后缀。例如,默认 OIDC 租户的会话 Cookie 名称为 q_session,但如果此属性设置为 test,则可以更改为 q_session_test

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_COOKIE_SUFFIX

string

 

quarkus.oidc."tenant".authentication.cookie-path

Cookie path 参数值(如果设置了)用于为会话设置 path 参数,state 和 post logout cookies。如果设置,则 Cookie-path-header 属性会首先检查。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_COOKIE_PATH

string

/

quarkus.oidc."tenant".authentication.cookie-path-header

Cookie path header 参数值(如果设置)标识传入的 HTTP 标头,其值用于为会话、状态和发布 logout cookie 设置 path 参数。如果缺少标头,则会检查 cookie-path 属性。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_COOKIE_PATH_HEADER

string

 

quarkus.oidc."tenant".authentication.cookie-domain

Cookie 域参数值(如果设置了)用于会话,state 和 post logout cookies。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_COOKIE_DOMAIN

string

 

quarkus.oidc."tenant".authentication.cookie-same-site

会话 Cookie 的 SameSite 属性。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_COOKIE_SAME_SITE

strict,lax,none

lax

quarkus.oidc."tenant".authentication.allow-multiple-code-flows

如果存在状态 Cookie,则 状态 查询参数也必须存在,并且当重定向路径与当前路径匹配时,状态 Cookie 名称后缀和状态 Cookie 值必须与状态 查询参数的值匹配。但是,如果从同一浏览器中尝试多个身份验证,例如从不同的浏览器标签页中,则当前可用的状态 cookie 可能代表从另一个标签页启动的身份验证流,而不是与当前请求相关的。禁用此属性,以在同一浏览器中只允许单个授权代码流。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_ALLOW_MULTIPLE_CODE_FLOWS

布尔值

true

quarkus.oidc."tenant".authentication.fail-on-missing-state-param

如果 state cookie 存在但没有状态查询参数,则失败并显示 HTTP 401 错误。

当禁用多个身份验证或者重定向 URL 与原始请求 URL 匹配时,过时的状态 Cookie 可能会保留在之前失败的浏览器缓存中,并可在当前请求中可见。例如,如果 Single-page 应用(SPA)使用 XHR 处理重定向到不支持其授权端点的 CORS 的提供程序,浏览器会阻止它,并且 Quarkus 创建的状态 Cookie 保留在浏览器缓存中。当检测到旧的状态 cookie 时,quarkus 会报告身份验证失败,但找不到匹配的状态查询参数。

报告 HTTP 401 错误通常是在这种情况下执行的正确操作,它会最小化浏览器重定向循环的风险,但还可以 SPA 或 Quarkus 应用程序管理重定向方式识别问题。例如,可能需要启用 java-script-auto-redirect,或者将供应商重定向到配置了 redirect-path 的 URL,以避免此类错误。

但是,如果上述选项不合适,则将此属性设置为 false 可以帮助。这会导致新的身份验证重定向到 OpenId Connect 供应商。这样做可能会增加浏览器重定向循环的风险。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_FAIL_ON_MISSING_STATE_PARAM

布尔值

false

quarkus.oidc."tenant".authentication.user-info-required

如果此属性设为 true,则调用 OIDC UserInfo 端点。如果 quarkus.oidc.roles.sourceuserinfo. 或 quarkus.oidc.token.verify-access-token-with-user-infotruequarkus.oidc.authentication.id-token-required 被设置为 false,则启用此属性。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_USER_INFO_REQUIRED

布尔值

false

quarkus.oidc."tenant".authentication.session-age-extension

会话期限扩展(以分钟为单位)。默认情况下,用户会话年龄属性被设置为 ID 令牌生命周期的值,用户会被重定向到 OIDC 供应商,以在会话过期后重新验证。如果此属性设置为非零值,则在会话过期前可以刷新过期的 ID 令牌。如果没有启用 token.refresh-expired 属性,则此属性会被忽略。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_SESSION_AGE_EXTENSION

duration question circle

5M

quarkus.oidc."tenant".authentication.java-script-auto-redirect

如果此属性设为 true,则返回普通的 302 重定向响应,如果请求是由 JavaScript API (如 XMLHttpRequest 或 Fetch)启动,且当前用户需要(re) authenticated,这可能不适用于单页应用程序(SPA),因为它自动遵循该 OIDC 授权端点通常不支持 CORS。

如果此属性设为 false,则返回 499 状态代码,以允许 SPA 在找到以 JavaScript 请求身份识别当前请求的请求标头时手动处理重定向。如果启用此属性,则默认预期 X-Requested-With 请求标头,其值设为 JavaScriptXMLHttpRequest。您可以注册自定义 JavaScriptRequestChecker 来执行自定义 JavaScript 请求检查。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_JAVA_SCRIPT_AUTO_REDIRECT

布尔值

true

quarkus.oidc."tenant".authentication.id-token-required

当授权代码流完成后,要求 ID 令牌可用。仅在您需要将授权代码流与 OAuth2 供应商(没有返回 ID 令牌)搭配使用时禁用此属性 - 在这种情况下会生成内部 IdToken。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_ID_TOKEN_REQUIRED

布尔值

true

quarkus.oidc."tenant".authentication.internal-id-token-lifespan

内部 ID 令牌寿命.只有在 Oauth2 供应商没有返回 IdToken 时,才会检查此属性。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_INTERNAL_ID_TOKEN_LIFESPAN

duration question circle

5M

quarkus.oidc."tenant".authentication.pkce-required

要求使用代码交换证明密钥(PKCE)。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_PKCE_REQUIRED

布尔值

false

quarkus.oidc."tenant".authentication.state-secret

用于为代码交换(PKCE)代码验证器(PKCE)代码验证器和/或非代码流状态加密概念验证的 secret。此 secret 应该至少为 32 个字符。

如果没有设置此 secret,则会检查使用 quarkus.oidc.credentials.secretquarkus.oidc.credentials.client-secret.value 配置的客户端 secret。最后,检查可用于 client_ jwt_secret 身份验证的 quarkus.oidc.credentials.jwt.secret。如果客户端 secret 小于 32 个字符,则不会将客户端 secret 用作状态加密 secret。

如果在检查所有这些属性后仍然未初始化,则自动生成该 secret。

如果 secret 长度小于 16 个字符,则报告错误。

环境变量: QUARKUS_OIDC__TENANT__AUTHENTICATION_STATE_SECRET

string

 

quarkus.oidc."tenant".code-grant.extra-params

除了所需的 代码和 redirect-uri 参数外,还必须包含其他参数,才能完成授权代码授权请求。

环境变量: QUARKUS_OIDC__TENANT__CODE_GRANT_EXTRA_PARAMS

Map<String,String>

 

quarkus.oidc."tenant".code-grant.headers

必须发送自定义 HTTP 标头来完成授权代码授权请求。

环境变量: QUARKUS_OIDC__TENANT__CODE_GRANT_HEADERS

Map<String,String>

 

quarkus.oidc."tenant".token-state-manager.strategy

默认 TokenStateManager 策略。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_STATE_MANAGER_STRATEGY

工具提示:keep-all-tokens[Keep ID, access and refresh token.], tooltip:id-token[Keep ID token only], tooltip:id-refresh-tokens[Keep ID and refresh token only]

keep-all-tokens

quarkus.oidc."tenant".token-state-manager.split-tokens

默认 TokenStateManager 会保留在授权代码中返回的所有令牌(ID、访问和刷新)默认授予单个会话 Cookie 的响应。启用此属性最小化会话 Cookie 大小

环境变量: QUARKUS_OIDC__TENANT_TOKEN_STATE_MANAGER_SPLIT_TOKENS

布尔值

false

quarkus.oidc."tenant".token-state-manager.encryption-required

强制 Default TokenStateManager 加密存储令牌的会话 Cookie。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_STATE_MANAGER_ENCRYPTION_REQUIRED

布尔值

true

quarkus.oidc."tenant".token-state-manager.encryption-secret

Default TokenStateManager 用来加密在启用 encryption-required 属性时存储令牌的会话 Cookie 的 secret。

如果没有设置此 secret,则会检查使用 quarkus.oidc.credentials.secretquarkus.oidc.credentials.client-secret.value 配置的客户端 secret。最后,检查可用于 client_ jwt_secret 身份验证的 quarkus.oidc.credentials.jwt.secret。如果在检查所有这些属性后仍然未初始化,则自动生成该 secret。

用于加密令牌的 secret 的长度应至少为 32 个字符。如果 secret 长度小于 16 个字符,则会记录警告信息。

环境变量: QUARKUS_OIDC__TENANT_TOKEN_STATE_MANAGER_ENCRYPTION_SECRET

string

 

quarkus.oidc."tenant".allow-token-introspection-cache

允许缓存令牌内省数据。请注意,启用此属性不启用缓存本身,但仅允许缓存给定租户的令牌内省。如果可以使用默认令牌缓存,请参阅 OidcConfig.TokenCache 来启用它。

环境变量: QUARKUS_OIDC__TENANT__ALLOW_TOKEN_INTROSPECTION_CACHE

布尔值

true

quarkus.oidc."tenant".allow-user-info-cache

允许缓存用户信息数据。请注意,启用此属性不启用缓存本身,但只允许缓存给定租户的用户信息数据。如果可以使用默认令牌缓存,请参阅 OidcConfig.TokenCache 来启用它。

环境变量: QUARKUS_OIDC__TENANT__ALLOW_USER_INFO_CACHE

布尔值

true

quarkus.oidc."tenant".cache-user-info-in-idtoken

允许在 IdToken 中简化 UserInfo,而不是将其缓存在令牌缓存中。只有在 Oauth2 供应商没有返回 IdToken 时,才会检查此属性。在生成的 IdToken 中,Inlining UserInfo 允许将其存储在会话 Cookie 中,并避免引入缓存的状态。

环境变量: QUARKUS_OIDC__TENANT_CACHE_USER_INFO_IN_IDTOKEN

布尔值

false

quarkus.oidc."tenant".jwks.resolve-early

如果在连接到 OIDC 供应商时,应该获取 JWK 验证密钥。

禁用此属性会延迟密钥获取,直到必须验证当前令牌的时间。通常,只有在令牌或其他 telated 请求属性提供正确解析密钥所需的额外上下文时,才能需要它。

环境变量: QUARKUS_OIDC__TENANT__JWKS_RESOLVE_EARLY

布尔值

true

quarkus.oidc."tenant".jwks.cache-size

可以缓存的最大 JWK 密钥数。如果 resolve-early 属性设为 true,则此属性会被忽略。

环境变量: QUARKUS_OIDC__TENANT__JWKS_CACHE_SIZE

int

10

quarkus.oidc."tenant".jwks.cache-time-to-live

可以缓存 JWK 密钥的分钟数。如果 resolve-early 属性设为 true,则此属性会被忽略。

环境变量: QUARKUS_OIDC__TENANT__JWKS_CACHE_TIME_TO_LIVE

duration question circle

10M

quarkus.oidc."tenant".jwks.clean-up-timer-interval

缓存计时器间隔。如果设置了此属性,则计时器会定期检查并删除过时的条目。如果 resolve-early 属性设为 true,则此属性会被忽略。

环境变量: QUARKUS_OIDC__TENANT__JWKS_CLEAN_UP_TIMER_INTERVAL

duration question circle

 

quarkus.oidc."tenant".provider

已知的 OpenId Connect 供应商标识符

环境变量: QUARKUS_OIDC__TENANT__PROVIDER

Apple,discord,facebook,github,google,linkedin,mas libpmemn,microsoft,spotify,strava,twitch,twitter,x

 
关于 Duration 格式

要写入持续时间值,请使用标准 java.time.Duration 格式。如需更多信息,请参阅 Duration#parse ()Java API 文档

您还可以使用简化的格式,从数字开始:

  • 如果值只是一个数字,它代表时间(以秒为单位)。
  • 如果值为数字,后跟 ms,代表时间(毫秒)。

在其他情况下,简化的格式被转换为 java.time.Duration 格式以进行解析:

  • 如果该值是一个数字,后跟 hms,则前缀为 PT
  • 如果值为数字,后跟 d,则会以 P 为前缀。

6.1. 参考

法律通告

Copyright © 2025 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2026 Red Hat
返回顶部