安全架构


Red Hat build of Quarkus 3.8

Red Hat Customer Content Services

摘要

Quarkus 安全架构通过 HttpAuthenticationMechanism 接口为 HTTP 应用程序提供通用身份验证机制和可自定义的安全性。探索根据您的需要量身定制的身份验证选项范围,并了解验证用户身份中的身份提供程序的角色,以及使用 SecurityIdentity 实例管理访问权限。该框架还支持主动身份验证,允许在各种应用上下文中实现自定义设置和高效的异常处理。

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

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

步骤

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

使开源包含更多

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

第 1 章 Quarkus 安全架构

Quarkus 安全架构提供多个内置身份验证机制,并且高度自定义。在 Quarkus 中保护 HTTP 应用程序的主要机制是 HttpAuthenticationMechanism 接口。

1.1. Quarkus 安全架构概述

当客户端发送 HTTP 请求时,Quarkus Security 通过与几个内置核心组件(包括 HttpAuthenticationMechanismIdentityProviderSecurityIdentityAugmentor )交互来编排安全身份验证和授权。

后续安全验证过程会产生三个结果之一:

  • HTTP 请求经过身份验证和授权,并被授予对 Quarkus 应用的访问权限。
  • HTTP 请求身份验证失败,请求者收到特定于身份验证机制的质询,如 401 错误、重定向到重新验证的 URL 或某些其他自定义身份验证质询响应。有关挑战响应的实际示例,请参阅 Quarkus 安全提示 和 Tricks 指南。
  • HTTP 请求授权失败,请求者会被拒绝访问 Quarkus 应用。

下图显示了 Quarkus 安全架构的详细流程流程:

图 1.1. Quarkus 安全架构和进程流

1.2. Quarkus 安全架构的核心组件

1.2.1. HttpAuthenticationMechanism

Quarkus Security 使用 HttpAuthenticationMechanism 从 HTTP 请求中提取身份验证凭据,并将它们委派为 IdentityProvider,将凭据转换为 SecurityIdentity。例如,凭据可以来自 Authorization 标头、客户端 HTTPS 证书或 Cookie。

当 Quarkus Security 拒绝身份验证请求时,HttpAuthenticationMechanism 会向客户端返回一个身份验证质询。挑战类型取决于身份验证机制。例如,使用 OIDC OpenID Connect (OIDC)授权代码流机制,会生成一个重定向 URL,客户端会返回到 OpenID Connect 供应商进行验证。

1.2.2. IdentityProvider

IdentityProvider 验证身份验证凭据并将其映射到 SecurityIdentity,其具有用户名、角色、原始身份验证凭据和其他属性。

您可以注入每个经过身份验证的用户的 SecurityIdentity 实例,以获取经过身份验证的身份信息。

在其他上下文中,可以具有相同信息或部分信息的其他并行表示,例如,Jakarta REST 的 SecurityContextJsonWebToken 用于 JSON Web 令牌(JWT)。

如需更多信息,请参阅 Quarkus 身份提供程序 指南。

1.2.3. SecurityIdentityAugmentor

由于 Quarkus 安全性是可自定义的,例如,您可以将授权角色添加到 SecurityIdentity,并优先选择一个或多个 SecurityAugmentor 实现。

在安全身份验证过程的最终阶段调用 SecurityIdentityAugmentor 的注册实例。如需更多信息,请参阅" 安全提示 和 Tricks"指南中的安全身份自定义 部分。

1.3. 支持的验证机制

Quarkus 安全框架支持多种身份验证机制,也可以组合使用。某些支持的验证机制内置在 Quarkus 中,而其他的验证机制则要求您添加扩展。

要了解 Quarkus 中的安全身份验证以及支持的机制和协议,请参阅 Quarkus 指南中的 Quarkus 身份验证机制

1.4. 主动身份验证

在 Quarkus 中默认启用主动身份验证。如果传入请求具有凭证,即使目标页面不需要身份验证,该请求也会始终被验证。如需更多信息,请参阅 Quarkus 主动身份验证 指南。

1.5. Quarkus 安全自定义

Quarkus 安全性可自定义。您可以自定义 Quarkus 的以下核心安全组件:

  • HttpAuthenticationMechanism
  • IdentityProvider
  • SecurityidentityAugmentor

有关自定义 Quarkus 安全的更多信息,包括被动安全性以及如何注册安全供应商,请参阅 Quarkus 安全提示和技巧 指南。

1.6. 参考

第 2 章 Quarkus 中的身份验证机制

Quarkus 安全框架支持多个身份验证机制,可用于保护应用程序的安全。您还可以组合身份验证机制。

提示

在选择保护 Quarkus 应用程序的身份验证机制前,请查看提供的信息。

2.1. 支持的身份验证机制概述

某些支持的验证机制内置在 Quarkus 中,而其他的验证机制则要求您添加扩展。以下部分详细介绍了所有这些机制:

下表将特定的验证要求映射到您可以在 Quarkus 中使用的支持机制:

Expand
表 2.1. 身份验证要求和机制
身份验证要求身份验证机制

用户名和密码

基本的 ,基于表单的身份验证

bearer 访问令牌

OIDC Bearer 令牌身份验证,JWT

单点登录(SSO)

OIDC 代码流 ,基于表单的身份验证

客户端证书

双向 TLS 身份验证

如需更多信息,请参阅以下 Token 验证机制比较 表。

2.2. 内置身份验证机制

Quarkus Security 提供以下内置身份验证支持:

2.2.1. 基本身份验证(Basic authentication)

您可以使用内置的 HTTP 基本身份验证机制来保护 Quarkus 应用程序端点。如需更多信息,请参阅以下文档:

2.2.2. 基于表单的身份验证

Quarkus 提供基于表单的身份验证,其的工作方式类似于传统的 Servlet 基于表单的身份验证。与传统的表单身份验证不同,经过身份验证的用户没有存储在 HTTP 会话中,因为 Quarkus 不支持集群的 HTTP 会话。相反,身份验证信息存储在加密的 cookie 中,该 Cookie 可以被共享同一加密密钥的所有群集成员读取。

要应用加密,请添加 quarkus.http.auth.session.encryption-key 属性,并确保您设置的值至少为 16 个字符。使用 SHA-256 对加密密钥进行哈希处理。生成的摘要用作 Cookie 值的 AES-256 加密的密钥。Cookie 包含作为加密值一部分的过期时间,因此集群中的所有节点都必须同步其时钟。一分钟内,如果会话正在使用,则使用更新的到期时间生成一个新的 Cookie。

使用单页应用程序(SPA)时,您通常希望通过删除默认页面路径来避免重定向,如下例所示:

# do not redirect, respond with HTTP 200 OK
quarkus.http.auth.form.landing-page=

# do not redirect, respond with HTTP 401 Unauthorized
quarkus.http.auth.form.login-page=
quarkus.http.auth.form.error-page=

# HttpOnly must be false if you want to log out on the client; it can be true if logging out from the server
quarkus.http.auth.form.http-only-cookie=false
Copy to Clipboard Toggle word wrap

现在,您已禁用了 SPA 的重定向,您必须以编程方式从客户端注销。以下是用于登录 j_security_check 端点并通过销毁 cookie 注销应用的 JavaScript 方法示例。

const login = () => {
    // Create an object to represent the form data
    const formData = new URLSearchParams();
    formData.append("j_username", username);
    formData.append("j_password", password);

    // Make an HTTP POST request using fetch against j_security_check endpoint
    fetch("j_security_check", {
        method: "POST",
        body: formData,
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
        },
    })
    .then((response) => {
        if (response.status === 200) {
            // Authentication was successful
            console.log("Authentication successful");
        } else {
            // Authentication failed
            console.error("Invalid credentials");
        }
    })
    .catch((error) => {
        console.error(error);
    });
};
Copy to Clipboard Toggle word wrap

要从客户端注销 SPA,cookie 必须设置为 quarkus.http.auth.form.http-only-cookie=false,以便您可以销毁 cookie,并可能重定向到您的主页面。

const logout= () => {
    // delete the credential cookie, essentially killing the session
    const removeCookie = `quarkus-credential=; Max-Age=0;path=/`;
    document.cookie = removeCookie;

    // perform post-logout actions here, such as redirecting back to your login page
};
Copy to Clipboard Toggle word wrap

要从服务器的 SPA 注销,可以将 Cookie 设置为 quarkus.http.auth.form.http-only-cookie=true,并使用此示例代码销毁 Cookie。

@ConfigProperty(name = "quarkus.http.auth.form.cookie-name")
String cookieName;

@Inject
CurrentIdentityAssociation identity;

@POST
public Response logout() {
    if (identity.getIdentity().isAnonymous()) {
        throw new UnauthorizedException("Not authenticated");
    }
    final NewCookie removeCookie = new NewCookie.Builder(cookieName)
            .maxAge(0)
            .expiry(Date.from(Instant.EPOCH))
            .path("/")
            .build();
    return Response.noContent().cookie(removeCookie).build();
}
Copy to Clipboard Toggle word wrap

以下属性可用于配置基于表单的身份验证:

lock 构建时修复的配置属性 - 所有其他配置属性可在运行时覆盖

Expand

Configuration 属性

类型

default

lock quarkus.http.auth.form.enabled

如果启用了表单身份验证。

环境变量: QUARKUS_HTTP_AUTH_FORM_ENABLED

布尔值

false

lock quarkus.http.auth.form.post-location

后位置。

环境变量: QUARKUS_HTTP_AUTH_FORM_POST_LOCATION

string

/j_security_check

lock 构建时修复的配置属性 - 所有其他配置属性可在运行时覆盖

Expand

Configuration 属性

类型

default

quarkus.http.auth.certificate-role-properties

包含客户端证书通用名称(CN)到角色映射的属性文件。仅在使用 quarkus.http.ssl.client-auth=requiredquarkus.http.ssl.client-auth=request 启用 mTLS 身份验证机制时才使用它。

属性文件应该具有 CN=role1,role,…​,roleN 格式,应该使用 UTF-8 进行编码。

环境变量: QUARKUS_HTTP_AUTH_CERTIFICATE_ROLE_PROPERTIES

path

 

quarkus.http.auth.realm

身份验证域

环境变量: QUARKUS_HTTP_AUTH_REALM

string

 

quarkus.http.auth.form.login-page

登录页面。可以通过设置 quarkus.http.auth.form.login-page= 来禁用重定向到登录页面。

环境变量: QUARKUS_HTTP_AUTH_FORM_LOGIN_PAGE

string

/login.html

quarkus.http.auth.form.username-parameter

username 字段名称。

环境变量: QUARKUS_HTTP_AUTH_FORM_USERNAME_PARAMETER

string

j_username

quarkus.http.auth.form.password-parameter

password 字段名称。

环境变量: QUARKUS_HTTP_AUTH_FORM_PASSWORD_PARAMETER

string

j_password

quarkus.http.auth.form.error-page

错误页面。可以通过设置 quarkus.http.auth.form.error-page= 来禁用重定向到错误页面。

环境变量: QUARKUS_HTTP_AUTH_FORM_ERROR_PAGE

string

/error.html

quarkus.http.auth.form.landing-page

如果没有要重新重定向到的保存页面,则要重定向到的登录页面。可以通过设置 quarkus.http.auth.form.landing-page= 来禁用登录页面。

环境变量: QUARKUS_HTTP_AUTH_FORM_LANDING_PAGE

string

/index.html

quarkus.http.auth.form.location-cookie

控制用于重定向用户要访问的位置的 Cookie 名称的选项。

环境变量: QUARKUS_HTTP_AUTH_FORM_LOCATION_COOKIE

string

quarkus-redirect-location

quarkus.http.auth.form.timeout

达到不活跃超时时不活动(空闲)超时,Cookie 不会被续订,并强制进行新的登录。

环境变量: QUARKUS_HTTP_AUTH_FORM_TIMEOUT

duration question circle

PT30M

quarkus.http.auth.form.new-cookie-interval

Cookie 在被替换为更新超时的新 Cookie 之前可以如何替换它,也称为"renewal-timeout"。请注意,较小的值会稍微多于服务器负载(因为新的加密 Cookie 将更频繁地生成);但是,较大的值会影响不活动超时,因为在生成 Cookie 时设置了超时。例如,如果将其设置为 10 分钟,并且不活跃超时为 30m,如果用户的最后请求是 Cookie,则实际超时会在最后一次请求后发生 21m,因为仅在生成新 Cookie 时刷新超时。也就是说,服务器端不会跟踪超时;时间戳在 Cookie 本身中经过编码和加密,并且会为每个请求解密并解析。

环境变量: QUARKUS_HTTP_AUTH_FORM_NEW_COOKIE_INTERVAL

duration question circle

PT1M

quarkus.http.auth.form.cookie-name

用于存储持久会话的 Cookie

环境变量: QUARKUS_HTTP_AUTH_FORM_COOKIE_NAME

string

quarkus-credential

quarkus.http.auth.form.cookie-path

会话和位置 Cookie 的 Cookie 路径。

环境变量: QUARKUS_HTTP_AUTH_FORM_COOKIE_PATH

string

/

quarkus.http.auth.form.http-only-cookie

设置 HttpOnly 属性,以防止通过 JavaScript 访问 Cookie。

环境变量: QUARKUS_HTTP_AUTH_FORM_HTTP_ONLY_COOKIE

布尔值

false

quarkus.http.auth.form.cookie-same-site

会话和位置 Cookie 的 SameSite 属性。

环境变量: QUARKUS_HTTP_AUTH_FORM_COOKIE_SAME_SITE

strict,lax,none

strict

quarkus.http.auth.permission."permissions"

确定是否启用整个权限集。默认情况下,如果定义了权限集,它会被启用。

环境变量: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__ENABLED

布尔值

 

quarkus.http.auth.permission."permissions"

此权限集链接到的 HTTP 策略。有三个内置策略:allow、deny 和 authentication。可以根据角色的策略定义,扩展也可以添加自己的策略。

环境变量: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__POLICY

string

必需 exclamation circle

quarkus.http.auth.permission."permissions"

此权限集应用到的方法。如果没有设置,则它们适用于所有方法。请注意,如果请求与任何权限集的路径匹配,但由于未列出方法,不匹配约束,则请求将被拒绝。特定于方法的权限优先于没有设置任何方法的匹配项。这意味着,例如,如果 Quarkus 配置为允许 GET 和 POST 请求发送到 /admin,且没有将 PUT 请求配置为 /admin,则拒绝将 PUT 请求配置为 /admin。

环境变量: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__METHODS

字符串列表

 

quarkus.http.auth.permission."permissions"

此权限检查应用到的路径。如果路径以 VRF 结尾,则它将被视为路径前缀,否则它将被视为完全匹配。匹配按长度进行,因此最具体的路径匹配具有优先权。如果多个权限集与同一路径匹配,则显式方法匹配优先于没有设置方法的匹配项,否则会应用限制性最强的权限。

环境变量: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__PATHS

字符串列表

 

quarkus.http.auth.permission."permissions".auth-mechanism

特定于路径的验证机制,必须用于验证用户。它需要匹配 HttpCredentialTransport 身份验证方案,如 'basic'、'bearer'、'form' 等。

环境变量: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__AUTH_MECHANISM

string

 

quarkus.http.auth.permission."permissions"

表示此策略总是适用于匹配的路径,除了具有获奖路径的策略之外。避免创建多个共享策略,以最大程度降低性能影响。

环境变量: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__SHARED

布尔值

false

quarkus.http.auth.policy."role-policy".roles-allowed

允许访问此策略保护的资源的角色。默认情况下,允许访问任何经过身份验证的用户。

环境变量: QUARKUS_HTTP_AUTH_POLICY__ROLE_POLICY__ROLES_ALLOWED

字符串列表

**

quarkus.http.auth.policy."role-policy".roles

根据 SecurityIdentity 已具有的角色,为 SecurityIdentity 添加授予的角色。例如,Quarkus OIDC 扩展可以从验证的 JWT 访问令牌中映射角色,您可能希望将其重新映射到部署特定的角色。

环境变量: QUARKUS_HTTP_AUTH_POLICY__ROLE_POLICY__ROLES

Map<String,List<String>>

 

quarkus.http.auth.policy."role-policy".permissions

如果此策略成功应用,则授予 SecurityIdentity 的权限(策略允许请求继续),并且经过身份验证的用户需要角色。例如,您可以通过设置 quarkus.http.auth.policy.role-policy1.permissions. admin =perm1:action1,perm1: action2 配置属性,将权限 perm1 映射到角色 admin授予的权限用于带有 @PermissionsAllowed 注释的授权。

环境变量: QUARKUS_HTTP_AUTH_POLICY__ROLE_POLICY__PERMISSIONS

Map<String,List<String>>

 

quarkus.http.auth.policy."role-policy".permission-class

此策略授予的权限将使用此配置属性指定的 java.security.Permission 实现创建。权限类必须准确声明一个构造器,它接受权限名称(字符串)或权限名称和操作(字符串,String[])。如果您以原生模式运行应用程序,则必须注册权限类来反映。

环境变量: QUARKUS_HTTP_AUTH_POLICY__ROLE_POLICY__PERMISSION_CLASS

string

io.quarkus.security.StringPermission

关于 Duration 格式

要写入持续时间值,请使用标准的 java.time.Duration 格式。如需更多信息,请参阅 Duration#parse ()Java API 文档

您还可以使用简化的格式,从数字开始:

  • 如果该值只是一个数字,则代表以秒为单位。
  • 如果值是数字,后跟 ms,则表示时间(毫秒)。

在其他情况下,简化的格式转换为 java.time.Duration 格式进行解析:

  • 如果该值是一个数字,后跟 hms,则使用 PT 前缀。
  • 如果该值是一个数字,后跟 d,则前缀为 P

2.2.3. 双向 TLS 身份验证

Quarkus 提供 mutual TLS (mTLS)身份验证,以便您可以根据其 X.509 证书验证用户。

要使用此验证方法,您必须首先为应用程序启用 SSL/TLS。如需更多信息,请参阅 Quarkus "HTTP 参考"指南中的支持使用 SSL/TLS 的安全连接 部分。

应用程序接受安全连接后,下一步是将 quarkus.http.ssl.certificate.trust-store-file 属性配置包含应用程序信任的所有证书的名称。指定文件还包括应用程序在客户端(如浏览器或其他服务)时如何询问证书的信息,尝试访问其中一个受保护的资源。

quarkus.http.ssl.certificate.key-store-file=server-keystore.jks            
1

quarkus.http.ssl.certificate.key-store-password=the_key_store_secret
quarkus.http.ssl.certificate.trust-store-file=server-truststore.jks        
2

quarkus.http.ssl.certificate.trust-store-password=the_trust_store_secret
quarkus.http.ssl.client-auth=required                                      
3

quarkus.http.auth.permission.default.paths=/*                              
4

quarkus.http.auth.permission.default.policy=authenticated
quarkus.http.insecure-requests=disabled                                    
5
Copy to Clipboard Toggle word wrap
1
服务器私钥所在的密钥存储。
2
加载可信证书的信任存储。
3
将值设为 required 时,服务器需要客户端证书。将值设为 REQUEST 以允许服务器在没有证书的情况下接受请求。当支持 mTLS 之外的验证方法时,此设置很有用。
4
定义策略,其中只有经过身份验证的用户应该可以从应用程序访问资源。
5
您可以明确禁用普通 HTTP 协议,从而要求所有请求都使用 HTTPS。当您将 quarkus.http.ssl.client-auth 设置为 required 时,系统会自动将 quarkus.http.insecure-requests 设置为 disabled

当传入的请求与信任存储中的有效证书匹配时,应用程序可以通过注入 SecurityIdentity 来获取主题,如下所示:

获取主题

@Inject
SecurityIdentity identity;

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
    return String.format("Hello, %s", identity.getPrincipal().getName());
}
Copy to Clipboard Toggle word wrap

您还可以使用以下示例中介绍的代码获取证书:

获取证书

import java.security.cert.X509Certificate;
import io.quarkus.security.credential.CertificateCredential;

CertificateCredential credential = identity.getCredential(CertificateCredential.class);
X509Certificate certificate = credential.getCertificate();
Copy to Clipboard Toggle word wrap

2.2.3.1. 将证书属性映射到角色

客户端证书的信息可用于将角色添加到 Quarkus SecurityIdentity

在检查客户端证书的通用名称(CN)属性后,您可以在 SecurityIdentity 中添加新角色。添加新角色的最简单方法是使用 certificate 属性到角色映射功能。

例如,您可以更新部分中显示的属性,它引入了 Mutual TLS 身份验证,如下所示:

quarkus.http.ssl.certificate.key-store-file=server-keystore.jks
quarkus.http.ssl.certificate.key-store-password=the_key_store_secret
quarkus.http.ssl.certificate.trust-store-file=server-truststore.jks
quarkus.http.ssl.certificate.trust-store-password=the_trust_store_secret
quarkus.http.ssl.client-auth=required
quarkus.http.insecure-requests=disabled

quarkus.http.auth.certificate-role-properties=cert-role-mappings.properties 
1


quarkus.http.auth.permission.certauthenticated.paths=/*   
2

quarkus.http.auth.permission.certauthenticated.policy=role-policy-cert 
3

quarkus.http.auth.policy.role-policy-cert.roles-allowed=user,admin     
4
Copy to Clipboard Toggle word wrap
1
cert-role-mappings.properties classpath 资源包含证书的 CN 值映射,格式为 CN=roleCN=role1,role2 等。假设它包含三个条目: alice=user,admin,bob=userjdoe=tester
2 3 4
使用 HTTP 安全策略要求 SecurityIdentity 必须具有 useradmin 角色才能授权请求。

假定假定配置,如果客户端证书的 CN 属性等于 alicebob,则请求会被授权,如果它等于 jdoe,则请求会被禁止。

2.2.3.2. 使用证书属性增强 SecurityIdentity

如果自动映射 证书属性到 roles 选项不适合,则始终可以注册 SecurityIdentityAugmentor。自定义 SecurityIdentityAugmentor 可以检查不同客户端证书属性的值,并相应地增强 SecurityIdentity

有关自定义 SecurityIdentity 的更多信息,请参阅 Quarkus " 安全提示和技巧"指南中的安全身份自定义 部分。

2.3. 其他支持的身份验证机制

Quarkus 安全还通过扩展支持以下身份验证机制:

2.3.1. OpenID Connect 身份验证

OpenID Connect (OIDC)是一个在 OAuth 2.0 协议之上工作的身份层。OIDC 可让客户端应用程序根据 OIDC 供应商执行的身份验证来验证用户的身份,并检索有关该用户的基本信息。

Quarkus quarkus-oidc 扩展提供了一个被动、可互操作的、启用了多租户的 OIDC 适配器,它支持 Bearer 令牌和授权代码流身份验证机制。Bearer 令牌身份验证机制从 HTTP Authorization 标头中提取令牌。

Authorization Code 流机制将用户重定向到 OIDC 供应商,以验证用户的身份。用户重定向到 Quarkus 后,机制通过交换为 ID、访问和刷新令牌提供的代码来完成身份验证过程。

您可以使用可刷新的 JSON Web 密钥(JWK)集或内省来验证 ID 和访问 JSON Web 令牌(JWT)令牌。但是,不透明(也称为二进制令牌)只能远程内省。

注意

使用 Quarkus OIDC 扩展时,Bearer 令牌和授权代码流验证机制都使用 SmallRye JWT 身份验证来代表 JWT 令牌作为 MicroProfile JWT org.eclipse.microprofile.jwt.JsonWebToken

2.3.1.1. 用于 OIDC 身份验证的额外 Quarkus 资源

有关可用于保护 Quarkus 应用程序的 OIDC 身份验证和授权方法的更多信息,请参阅以下资源:

Expand
OIDC 主题Quarkus 信息资源

bearer 令牌身份验证机制

OIDC Bearer 令牌身份验证

授权代码流身份验证机制

OpenID Connect (OIDC)授权代码流机制

OIDC 和 SAML 身份代理

OpenID Connect (OIDC)授权代码流和 SAML Identity 代理

支持 Bearer 令牌身份验证或授权代码流机制的多个租户

使用 OpenID Connect (OIDC)多租户

使用常用的 OpenID Connect 供应商保护 Quarkus

配置已知的 OpenID Connect 供应商

使用 Keycloak 集中授权

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

注意

要在运行时启用 Quarkus OIDC 扩展,请在构建时设置 quarkus.oidc.tenant-enabled=false。然后,使用系统属性在运行时重新启用它。

有关在多租户 OIDC 部署中管理单个租户配置的更多信息,请参阅"使用 OpenID Connect (OIDC)多租户"指南中的 禁用 租户配置部分。

2.3.1.2. OpenID Connect 客户端和过滤器

quarkus-oidc-client 扩展为 OidcClient 提供 OidcClient,用于从支持以下令牌授予的 OpenID Connect 和 OAuth2 供应商中刷新访问令牌:

  • client-credentials
  • password
  • refresh_token

quarkus-oidc-client-filter 扩展需要 quarkus-oidc-client 扩展。它提供 JAX-RS RESTful Web Services OidcClientRequestFilter,它将 OidcClient 获取的访问令牌设置为 HTTP Authorization 标头的 Bearer scheme 值。此过滤器可以在注入当前 Quarkus 端点的 MicroProfile REST 客户端实现中注册,但它与此服务端点的身份验证要求无关。例如,它可以是一个公共端点,也可以使用 mTLS 进行保护。

重要

在这种情况下,您不需要使用 Quarkus OpenID Connect 适配器来保护 Quarkus 端点。

quarkus-oidc-token-propagation 扩展需要 quarkus-oidc 扩展。它提供 Jakarta REST TokenCredentialRequestFilter,它将 OpenID Connect Bearer 令牌或 Authorization Code Flow 访问令牌设置为 HTTP Authorization 标头的 Bearer scheme 值。此过滤器可以注册到注入当前 Quarkus 端点中的 MicroProfile REST 客户端实现,该端点必须使用 Quarkus OIDC 适配器进行保护。此过滤器可以将访问令牌传播到下游服务。

如需更多信息,请参阅 OpenID Connect 客户端和令牌传播快速启动OpenID Connect (OIDC)和 OAuth2 客户端和过滤器参考指南

2.3.2. 小的 JWT 身份验证

quarkus-smallrye-jwt 扩展提供 MicroProfile JSON Web Token (JWT) 2.1 实现,以及验证签名和加密的 JWT 令牌的多个选项。它将它们表示为 org.eclipse.microprofile.jwt.JsonWebToken

Quarkus-smallrye-jwtquarkus-oidc Bearer 令牌身份验证机制的替代选择,并使用 Privacy Enhanced Mail (PEM)密钥或 refreshable JWK 密钥集仅验证 JWT 令牌。Quarkus-smallrye-jwt 还提供 JWT 生成 API,可用于轻松创建 签名的内部签名和加密JWT 令牌。

如需更多信息,请参阅使用 JWT RBAC 指南。

使用以下信息来选择适当的令牌身份验证机制来保护 Quarkus 应用程序。

身份验证机制用例列表

  • Quarkus-oidc 需要 OpenID Connect 供应商,如 Keycloak,它可以验证 bearer 令牌或使用授权代码流验证最终用户。在这两种情况下,quarkus-oidc 需要连接到指定的 OpenID Connect 供应商。
  • 如果用户身份验证需要授权代码流,或者您需要支持多个租户,请使用 quarkus-oidcQuarkus-oidc 也可以使用授权代码流和 Bearer 访问令牌来请求用户信息。
  • 如果需要验证 bearer 令牌,请使用 quarkus-oidcquarkus-smallrye-jwt
  • 如果您的 bearer 令牌采用 JSON Web 令牌(JWT)格式,您可以使用前面的列表中的任何扩展。quarkus-oidcquarkus-smallrye-jwt 支持在 OpenID Connect 提供程序轮转密钥时刷新 JsonWebKey (JWK)设置。因此,如果必须避免远程令牌内省,或者供应商不支持,请使用 quarkus-oidcquarkus-smallrye-jwt 来验证 JWT 令牌。
  • 要远程内省 JWT 令牌,您可以使用 quarkus-oidc 通过远程内省验证不透明或二进制令牌。quarkus-smallrye-jwt 不支持对不透明或 JWT 令牌的远程内省,而是依赖于通常从 OpenID Connect 供应商检索的本地可用密钥。
  • Quarkus-oidcquarkus-smallrye-jwt 支持 JWT 和不透明令牌注入端点代码中。注入的 JWT 令牌提供有关用户的更多信息。所有扩展都可以将令牌作为 主体 注入。
  • quarkus-smallrye-jwt 支持比 quarkus-oidc 更多的键格式。Quarkus-oidc 只使用属于 JWK 集的 JWK 格式的密钥,而 quarkus-smallrye-jwt 支持 PEM 密钥。
  • Quarkus-smallrye-jwt 处理本地签名、内部签名和加密令牌。相反,虽然 quarkus-oidc 也可以验证这些令牌,但它将其视为不透明令牌,并通过远程内省进行验证。
注意

架构考虑因素导致您的决定使用不透明或 JSON Web 令牌(JWT)令牌格式。不透明令牌通常比 JWT 令牌更短,但需要大多数令牌关联状态才能在提供程序数据库中维护。不透明令牌是有效的数据库指针。

JWT 令牌比不透明令牌要长。然而,提供商通过将其存储为令牌声明并签名或加密,从而有效地将大多数令牌关联状态委派给客户端。

Expand
表 2.2. 令牌身份验证机制比较
所需功能身份验证机制
 

quarkus-oidc

quarkus-smallrye-jwt

bearer JWT 验证

本地验证或内省

本地验证

bearer opaque 令牌验证

内省

刷新 JsonWebKey 设置,以验证 JWT 令牌

将令牌表示为 Principal

将 JWT 注入为 MP JWT

授权代码流

多租户

用户信息支持

PEM 密钥格式支持

secretKey 支持

JSON Web 密钥(JWK)格式

内部签名和加密令牌

内省

本地验证

自定义令牌验证

带有注入的 JWT 解析器

JWT 作为 Cookie 支持

2.5. 合并身份验证机制

如果不同的源提供用户凭证,您可以组合身份验证机制。例如,您可以组合内置的 Basic 和 Quarkus quarkus-oidc Bearer 令牌身份验证机制。

重要

您不能组合 Quarkus quarkus-oidc Bearer 令牌和 smallrye-jwt 身份验证机制,因为这两种机制都试图验证从 HTTP Bearer 令牌身份验证方案中提取的令牌。

2.5.1. 特定于路径的身份验证机制

以下配置示例演示了如何为给定请求路径强制使用单一可选择的验证机制:

quarkus.http.auth.permission.basic-or-bearer.paths=/service
quarkus.http.auth.permission.basic-or-bearer.policy=authenticated

quarkus.http.auth.permission.basic.paths=/basic-only
quarkus.http.auth.permission.basic.policy=authenticated
quarkus.http.auth.permission.basic.auth-mechanism=basic

quarkus.http.auth.permission.bearer.paths=/bearer-only
quarkus.http.auth.permission.bearer.policy=authenticated
quarkus.http.auth.permission.bearer.auth-mechanism=bearer
Copy to Clipboard Toggle word wrap

确保 auth-mechanism 属性的值与 HttpAuthenticationMechanism 支持的身份验证方案匹配,如 basicbearerform

2.6. 主动身份验证

在 Quarkus 中默认启用主动身份验证。这意味着,如果传入的请求具有凭证,则请求将始终进行身份验证,即使目标页面不需要身份验证。如需更多信息,请参阅 Quarkus 主动身份验证 指南。

2.7. 参考

第 3 章 用户身份供应商

在 Quarkus 安全框架中,身份提供程序通过验证用户身份在身份验证和授权中发挥关键作用。IdentityProvider 创建一个 SecurityIdentity 实例,用于在用户身份验证过程中验证和授权对 Quarkus 应用的访问请求。

IdentityProviderHttpAuthenticationMechanism 提供的身份验证凭据转换为 SecurityIdentity 实例。

有些扩展(如 OIDCOAuth2SmallRye JWT )具有特定于支持的身份验证流的内联 IdentityProvider 实现。例如,quarkus-oidc 使用自己的 IdentityProvider 将令牌转换为 SecurityIdentity 实例。

如果使用基于 Basic 或表单的身份验证,您必须添加一个 IdentityProvider 个实例,才能将用户名和密码转换为 SecurityIdentity 实例。

要开始使用 Quarkus 中的安全性,请考虑将 Quarkus 内置基本 HTTP 身份验证与 Jakarta Persistence 身份提供程序相结合,以启用基于角色的访问控制(RBAC)。

有关基本身份验证、其机制和相关身份提供程序的更多信息,请参阅以下资源:

第 4 章 主动身份验证

了解如何在 Quarkus 中管理主动身份验证,包括自定义设置和处理异常。获取各种应用程序场景的实际见解和策略。

在 Quarkus 中默认启用主动身份验证。它确保所有带有凭证的传入请求都经过身份验证,即使目标页面不需要身份验证。因此,带有无效凭证的请求也会被拒绝,即使目标页面是公共的。

只有在目标页面需要它时,才能关闭此默认行为。要关闭主动身份验证,以便仅在目标页面需要它时进行身份验证,请按如下所示修改 application.properties 配置文件:

quarkus.http.auth.proactive=false
Copy to Clipboard Toggle word wrap

如果您关闭主动身份验证,则身份验证过程仅在请求身份时运行。可以请求身份,因为需要用户进行身份验证的安全规则,或者需要编程访问当前身份。

如果使用主动身份验证,则访问 SecurityIdentity 是一个阻塞操作。这是因为,身份验证可能还必须发生,并且访问 SecurityIdentity 可能需要对外部系统(如数据库)调用,这可能会阻止操作。对于阻塞应用程序,这不是一个问题。但是,如果您在被动应用程序中禁用了身份验证,此操作会失败,因为您无法在 I/O 线程中阻止操作。要临时解决这个问题,您需要 @Inject 一个 io.quarkus.security.identity.CurrentIdentityAssociation 实例,并调用 Uni<SecurityIdentity> getDeferredIdentity (); 方法。然后,您可以订阅生成的 Uni,以便在身份验证完成后获得通知,身份可用。

注意

您仍然可以从以 @RolesAllowed 、@Authenticated、@Authenticated 或通过相应配置授权检查标注的端点,在 RESTEasy Reactive 中异步访问 SecurityIdentity getIdentity (),因为身份验证已经发生。如果 路由响应同步,则同样适用于 Reactive 路由。

禁用主动身份验证后,如果未同步返回值的安全方法,则 CDI Bean 上使用 的标准安全注解 在 I/O 线程上无法正常工作。这个限制源自这些方法访问 SecurityIdentity 的必要性。

以下示例定义了 HelloResourceHelloService。任何对 /hello 的 GET 请求在 I/O 线程上运行,并抛出 BlockingOperationNotAllowedException 异常。

修复示例的方法多:

  • 通过注解带有 @Blockinghello 端点,切换到 worker 线程。
  • 使用被动或异步数据类型更改 sayHello 方法返回类型。
  • @RolesAllowed 注释移到端点。这可能是最安全的方法之一,因为从端点方法访问 SecurityIdentity 不是阻塞操作。
import jakarta.annotation.security.PermitAll;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import io.smallrye.mutiny.Uni;

@Path("/hello")
@PermitAll
public class HelloResource {

    @Inject
    HelloService helloService;

    @GET
    public Uni<String> hello() {
        return Uni.createFrom().item(helloService.sayHello());
    }

}
Copy to Clipboard Toggle word wrap
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class HelloService {

    @RolesAllowed("admin")
    public String sayHello() {
        return "Hello";
    }

}
Copy to Clipboard Toggle word wrap

4.1. 自定义身份验证异常响应

您可以使用 Jakarta REST ExceptionMapper 捕获 Quarkus 安全身份验证异常,如 io.quarkus.security.AuthenticationFailedException。例如:

package io.quarkus.it.keycloak;

import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;

import io.quarkus.security.AuthenticationFailedException;

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFailedExceptionMapper implements ExceptionMapper<AuthenticationFailedException> {

    @Context
    UriInfo uriInfo;

    @Override
    public Response toResponse(AuthenticationFailedException exception) {
        return Response.status(401).header("WWW-Authenticate", "Basic realm=\"Quarkus\"").build();
    }
}
Copy to Clipboard Toggle word wrap
Important

有些 HTTP 身份验证机制必须处理身份验证例外,才能创建正确的身份验证质询。例如: io.quarkus.oidc.runtime.CodeAuthenticationMechanism,它管理 OpenID Connect (OIDC)授权代码流身份验证,必须构建正确的重定向 URL 并设置状态 cookie。因此,避免使用自定义异常映射器来自定义此类机制抛出的身份验证异常。相反,一种安全的方法是确保启用主动身份验证并使用 Vert.x HTTP 路由失败处理程序。这是因为事件进入具有正确响应状态和标头的处理程序。然后,您必须只自定义响应,例如:

package io.quarkus.it.keycloak;

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

import io.quarkus.security.AuthenticationFailedException;
import io.vertx.core.Handler;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class AuthenticationFailedExceptionHandler {

    public void init(@Observes Router router) {
        router.route().failureHandler(new Handler<RoutingContext>() {
            @Override
            public void handle(RoutingContext event) {
                if (event.failure() instanceof AuthenticationFailedException) {
                    event.response().end("CUSTOMIZED_RESPONSE");
                } else {
                    event.next();
                }
            }
        });
    }
}
Copy to Clipboard Toggle word wrap

4.2. 参考

法律通告

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
返回顶部