第 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
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

Theme

© 2025 Red Hat