搜索

第 4 章 主动验证

download PDF

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

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

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

quarkus.http.auth.proactive=false

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

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

注意

您仍然可以从使用 @RolesAllowed 、@Authenticated、@Authenticated ,或具有相应配置授权检查的端点同时访问 Quarkus REST 中的 SecurityIdentity getIdentity () (以前为 RESTEasy Reactive)。如果路由响应是同步,则也对 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());
    }

}
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class HelloService {

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

}

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.Context;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
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();
    }
}
小心

有些 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();
                }
            }
        });
    }
}
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

© 2024 Red Hat, Inc.