2.5. 组合身份验证机制


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

当第一个 SecurityIdentity 由其中一个身份验证机制生成后,身份验证过程就会马上完成。

2.5.1. 包含的身份验证

在某些情况下,可能要求所有注册的身份验证机制都创建其 SecurityIdentity。当用户通过虚拟专用网络进行身份验证时,或者当前令牌必须绑定到令牌验证才能成功通过 Mutual TLS 身份验证时,可能需要使用令牌验证。

在 Quarkus 中,此类身份验证名为 inclusive,您可以启用它,如下所示:

quarkus.http.auth.inclusive=true
Copy to Clipboard Toggle word wrap

如果身份验证包含,则由第一个身份验证机制创建的 SecurityIdentity 可以注入到应用程序代码中。例如,如果需要 Mutual TLS 身份验证和 基本身份验证机制身份验证,则 Mutual TLS 身份验证机制 将首先创建 SecurityIdentity

注意

Mutual TLS 身份验证机制在启用包含身份验证时具有最高的优先级,以确保注入的 SecurityIdentity 始终代表 双向 TLS 身份验证,并可用于获取由其他身份验证机制提供的 SecurityIdentity 身份的访问。

可以在第一个 SecurityIdentity 上作为 quarkus.security.identities 属性访问额外的 SecurityIdentity 实例,但访问这些额外的身份可能并不需要访问这些额外身份,例如,当 Mutual TLS 身份验证和 OIDC Bearer 身份验证机制都已合并并完成其身份验证时,经过身份验证的 bearer 令牌可以注入令牌凭证,以及 Mutual TLS 身份验证 创建的 SecurityIdentity。下面是一个示例:

package org.acme.security;

import io.quarkus.oidc.AccessTokenCredential;
import io.quarkus.oidc.common.runtime.OidcConstants;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.vertx.http.runtime.security.HttpSecurityUtils;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

@ApplicationScoped
public class InclusiveAuthExampleBean {

    @Inject
    SecurityIdentity mtlsIdentity;  
1


    @Inject
    AccessTokenCredential accessTokenCredential;

    private AccessTokenCredential getAccessTokenCredential() {
        if (doItHardWay()) {
            var securityIdentities = HttpSecurityUtils.getSecurityIdentities(mtlsIdentity);    
2

            if (securityIdentities != null) {
                SecurityIdentity bearerIdentity = securityIdentities.get(OidcConstants.BEARER_SCHEME);
                if (bearerIdentity != null) {
                    return bearerIdentity.getCredential(AccessTokenCredential.class);
                }
            }
        }
        return accessTokenCredential;
    }

}
Copy to Clipboard Toggle word wrap
1
这是由具有最高优先级的适用身份验证机制创建的 SecurityIdentity
2
其他执行身份验证的身份验证机制,可在 SecurityIdentity 上可用。
重要

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

2.5.2. 基于路径的身份验证

以下配置示例演示了如何为给定请求路径强制执行单个可选择的身份验证机制:

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 支持的身份验证方案匹配,例如 基本的bearer表单

可以使用注解来选择特定于每个 Jakarta REST 端点的身份验证机制。只有在禁用 主动 身份验证时,此功能才会启用。因此,注解只能在与 REST 端点匹配后选择验证机制。以下是如何为每个 REST 端点选择身份验证机制:

quarkus.http.auth.proactive=false
Copy to Clipboard Toggle word wrap
import io.quarkus.oidc.AuthorizationCodeFlow;
import io.quarkus.vertx.http.runtime.security.annotation.BasicAuthentication;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@Path("hello")
public class HelloResource {

    @GET
    @BasicAuthentication 
1
 
2

    @Path("basic")
    public String basicAuthMechanism() {
        return "basic";
    }

    @GET
    @RolesAllowed("admin") 
3

    @AuthorizationCodeFlow 
4

    @Path("code-flow")
    public String codeFlowAuthMechanism() {
        return "code-flow";
    }
}
Copy to Clipboard Toggle word wrap
1
REST 端点 /hello/basic 只能通过 基本身份验证 访问。
2
此端点需要身份验证,因为当没有标准安全注释时,@BasicAuthentication 注释会被默认添加 @Authenticated 注释。
3
@AuthorizationCodeFlow 注释可以与任何其他标准安全注释(如 @RolesAllowed@PermissionsAllowed 等)结合使用。
4
REST 端点 /hello/code-flow 只能通过 OIDC 授权代码流机制 访问。
Expand
表 2.3. 支持的身份验证机制注解
身份验证机制^注解

基本身份验证机制

io.quarkus.vertx.http.runtime.security.annotation.BasicAuthentication

基于表单的验证机制

io.quarkus.vertx.http.runtime.security.annotation.FormAuthentication

双向 TLS 身份验证机制

io.quarkus.vertx.http.runtime.security.annotation.MTLSAuthentication

bearer 令牌身份验证机制

io.quarkus.oidc.BearerTokenAuthentication

OIDC 授权代码流机制

io.quarkus.oidc.AuthorizationCodeFlow

smallrye JWT 身份验证机制

io.quarkus.smallrye.jwt.runtime.auth.BearerTokenAuthentication

提示

Quarkus 会自动保护使用身份验证机制注解注解的端点。当 REST 端点和资源中没有标准安全注解时,会为您添加 io.quarkus.security.Authenticated 注解。

也可以使用 io.quarkus.vertx.http.runtime.security.annotation.HttpAuthenticationMechanism 注释来选择基于其方案的任何身份验证机制。基于注释的 analogy 到 quarkus.http.auth.permission.basic.auth-mechanism=custom 配置属性是 @HttpAuthenticationMechanism ("custom") 注释。

注意

为了与各种 Jakarta EE 规格保持一致,建议始终重复注释,而不依赖于注解继承。

默认情况下,Quarkus 只支持 每个路径的一个验证机制的基于路径的 验证。如果需要将多个身份验证机制用于基于路径的身份验证,您可以编写一个自定义 HttpAuthenticationMechanism 部分,如 Security Tips and Tricks 指南中有多个 HttpAuthenticationMechanism 部分所述。另一种选择是在 lax 模式中启用 Inclusive 身份验证,并编写自定义 HttpSecurityPolicyPermissionChecker,验证所有注册的 HTTP 身份验证机制是否创建了其机制特定的 SecurityIdentity

在 lax 模式中启用包含的身份验证

quarkus.http.auth.inclusive-mode=lax 
1

quarkus.http.auth.inclusive=true
Copy to Clipboard Toggle word wrap

1
默认情况下,包含的身份验证要求所有注册的 HTTP 身份验证机制都必须创建 SecurityIdentity。但是,在 lax 模式中,如果至少一个注册的 HttpAuthenticationMechanism 创建了 SecurityIdentity,则身份验证会成功。

假设我们有 3 个注册机制 mTLS、Basic 和 OIDC,您只需要 Basic 和 mTLS 身份验证才能成功访问 hello 方法。在这种情况下,在 lax 模式中启用包含的身份验证,可以检查生成身份的机制,如下例所示:

HTTP 身份验证机制检查示例

import io.quarkus.security.PermissionChecker;
import io.quarkus.security.PermissionsAllowed;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.vertx.http.runtime.security.HttpSecurityUtils;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import java.util.Map;

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

    @PermissionsAllowed("mtls-basic")
    @GET
    public String hello() {
        return "Hello world";
    }

    @PermissionChecker("mtls-basic")
    boolean isMtlsAndBasicAuthentication(SecurityIdentity identity) {
        Map<String, SecurityIdentity> identities = HttpSecurityUtils.getSecurityIdentities(identity);
        if (identities != null) {
            return identities.containsKey("basic") && identities.containsKey("x509"); 
1

        }
        return false;
    }
}
Copy to Clipboard Toggle word wrap

1
只有在确认 mTLS基本身份验证 机制都已验证当前请求时,才允许访问端点。

2.5.2.4. 如何将其与 HTTP 安全策略合并

定义允许访问单个资源的角色的最简单方法是 @RolesAllowed 注释。但是,也可以使用 HTTP 安全策略,如下例所示:

quarkus.http.auth.policy.roles1.roles-allowed=user
quarkus.http.auth.permission.roles1.paths=/hello/code-flow
quarkus.http.auth.permission.roles1.applies-to=JAXRS 
1

quarkus.http.auth.permission.roles1.policy=roles1
quarkus.http.auth.permission.roles1.methods=GET 
2
Copy to Clipboard Toggle word wrap
1
在选择了特定于端点的身份验证机制后,延迟此策略的权限检查。
2
使 roles1 权限仅与使用 @AuthorizationCodeFlow 注释标注的端点匹配。Unannotated 端点必须避免 apply -to=JAXRS 选项导致的延迟。
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat