AWS Lambda with Quarkus REST, Undertow, or Reactive Routes

有了 Quarkus,您可以使用 AWS Gateway HTTP APIAWS Gateway REST API将您最喜欢的 Java HTTP 框架部署为 AWS Lambda。这意味着您可以将使用 Quarkus REST(我们的 Jakarta REST 实现)、Undertow(servlet)、Reactive Routes、Funqy HTTP或任何其他 Quarkus HTTP 框架编写的微服务部署为 AWS Lambda。

With Quarkus you can deploy your favorite Java HTTP frameworks as AWS Lambda’s using either the AWS Gateway HTTP API or AWS Gateway REST API. This means that you can deploy your microservices written with Quarkus REST (our Jakarta REST implementation), Undertow (servlet), Reactive Routes, Funqy HTTP or any other Quarkus HTTP framework as an AWS Lambda.

您应该仅将单个 HTTP 框架与 AWS Lambda 扩展一起使用,以避免意外的冲突和错误。

You should only use single HTTP framework together with AWS Lambda extension to avoid unexpected conflicts and errors.

您可以将 Lambda 部署为纯 Java jar,也可以将项目编译为原生镜像并部署,以实现更小的内存占用和启动时间。我们的集成还会生成 SAM 部署文件, Amazon’s SAM framework可以使用这些文件。

You can deploy your Lambda as a pure Java jar, or you can compile your project to a native image and deploy that for a smaller memory footprint and startup time. Our integration also generates SAM deployment files that can be consumed by Amazon’s SAM framework.

Quarkus 为每个 Gateway API 提供不同的扩展。HTTP Gateway API 在 `quarkus-amazon-lambda-http`扩展中实现。REST Gateway API 在 `quarkus-amazon-lambda-rest`扩展中实现。如果您对使用哪个 Gateway 产品感到困惑,亚马逊有一个 great guide来帮助您进行权衡。

Quarkus has a different extension for each Gateway API. The HTTP Gateway API is implemented within the quarkus-amazon-lambda-http extension. The REST Gateway API is implemented within the quarkus-amazon-lambda-rest extension. If you are confused on which Gateway product to use, Amazon has a great guide to help you navigate this decision.

像大多数 Quarkus 扩展一样,Quarkus AWS Lambda HTTP/REST 扩展支持实时编码。

Like most Quarkus extensions, the Quarkus AWS Lambda HTTP/REST extensions support Live Coding. Unresolved directive in aws-lambda-http.adoc - include::{includes}/extension-status.adoc[]

Prerequisites

Unresolved directive in aws-lambda-http.adoc - include::{includes}/prerequisites.adoc[]* An Amazon AWS account* AWS SAM CLI

Unresolved directive in aws-lambda-http.adoc - include::{includes}/prerequisites.adoc[] * An Amazon AWS account * AWS SAM CLI

Getting Started

本指南指导你通过 Maven 原型生成示例 Java 项目。它随后介绍了项目的结构,以便你可以调整任何现有项目以使用 AWS Lambda。

This guide walks you through generating an example Java project via a Maven archetype. Later on, it walks through the structure of the project so you can adapt any existing projects you have to use AWS Lambda.

Installing AWS bits

安装所有 AWS 位可能是本指南中最困难的事情。请务必按照所有步骤安装 AWS SAM CLI。

Installing all the AWS bits is probably the most difficult thing about this guide. Make sure that you follow all the steps for installing AWS SAM CLI.

Creating the Maven Deployment Project

使用我们的 Maven 原型创建 Quarkus AWS Lambda Maven 项目。

Create the Quarkus AWS Lambda Maven project using our Maven Archetype.

如果你想使用 AWS Gateway HTTP API,请使用以下脚本生成你的项目:

If you want to use the AWS Gateway HTTP API, generate your project with this script:

mvn archetype:generate \
       -DarchetypeGroupId=io.quarkus \
       -DarchetypeArtifactId=quarkus-amazon-lambda-http-archetype \
       -DarchetypeVersion={quarkus-version}

如果你想使用 AWS Gateway REST API,请使用以下脚本生成你的项目:

If you want to use the AWS Gateway REST API, generate your project with this script:

mvn archetype:generate \
       -DarchetypeGroupId=io.quarkus \
       -DarchetypeArtifactId=quarkus-amazon-lambda-rest-archetype \
       -DarchetypeVersion={quarkus-version}

Build and Deploy

构建项目:

Build the project:

Unresolved directive in aws-lambda-http.adoc - include::{includes}/devtools/build.adoc[]

这会编译代码并运行生成项目中包含的单元测试。单元测试与任何其他 Java 项目相同,不需要在 Amazon 上运行。Quarkus 开发模式也可用作此扩展。

This will compile the code and run the unit tests included within the generated project. Unit testing is the same as any other Java project and does not require running on Amazon. Quarkus dev mode is also available with this extension.

如果你想构建一个本机可执行文件,请确保正确安装 GraalVM,并向构建添加 native 属性

If you want to build a native executable, make sure you have GraalVM installed correctly and just add a native property to the build

Unresolved directive in aws-lambda-http.adoc - include::{includes}/devtools/build-native.adoc[]

如果你不是在 Linux 系统上构建,你还需要传递一个属性来指示 quarkus 使用 Docker 构建,因为 AmazonLambda 需要 Linux 二进制文件。你可以通过将 -Dquarkus.native.container-build=true 传递给构建命令来执行此操作。不过,这需要你在本地安装 Docker。

If you are building on a non-Linux system, you will need to also pass in a property instructing quarkus to use a Docker build as Amazon Lambda requires Linux binaries. You can do this by passing -Dquarkus.native.container-build=true to your build command. This requires you to have Docker installed locally, however.

Unresolved directive in aws-lambda-http.adoc - include::{includes}/devtools/build-native-container.adoc[]

Extra Build Generated Files

运行构建后,你使用的 Quarkus lambda 扩展会生成几个额外文件。这些文件位于构建目录中:Maven 的 target/ ,Gradle 的 build/

After you run the build, there are a few extra files generated by the Quarkus lambda extension you are using. These files are in the build directory: target/ for Maven, build/ for Gradle.

  • function.zip - lambda deployment file

  • sam.jvm.yaml - sam cli deployment script

  • sam.native.yaml - sam cli deployment script for native

Live Coding and Simulating AWS Lambda Environment Locally

在开发和测试模式下,Quarkus 将启动一个模拟 AWS Lambda 事件服务器,该服务器会将 HTTP 请求转换为相应的 API Gateway 事件类型,并将其发布到底层的 Quarkus HTTP lambda 环境进行处理。这尽可能地在本地模拟 AWS Lambda 环境,而无需 Docker 和 SAM CLI 等工具。

In dev and test mode, Quarkus will start a mock AWS Lambda event server that will convert HTTP requests to the corresponding API Gateway event types and post them to the underlying Quarkus HTTP lambda environment for processing. This simulates the AWS Lambda environment as much as possible locally without requiring tools like Docker and SAM CLI.

在使用 Quarkus 开发模式时,只要像通常测试 REST 端点时一样在 http://localhost:8080 上调用 HTTP 请求。此请求将命中模拟事件服务器,并将转换为 Quarkus Lambda 轮询循环使用的 API Gateway json 消息。

When using Quarkus Dev Mode just invoke HTTP requests on http://localhost:8080 as you normally would when testing your REST endpoints. This request will hit the Mock Event Server and will be converted to the API Gateway json message that is consumed by the Quarkus Lambda Poll loop.

为了进行测试,Quarkus 在 8081 端口下启动一个单独的模拟事件服务器。Rest Assured 的默认端口由 Quarkus 自动设置为 8081,因此你不必担心设置此端口。

For testing, Quarkus starts up a separate Mock Event server under port 8081. The default port for Rest Assured is automatically set to 8081 by Quarkus, so you don’t have to worry about setting this up.

如果你想在测试中模拟更复杂的 API Gateway 事件,请手动使用原始 API Gateway json 事件以 HTTP POST 方式访问 http://localhost:8080/lambda (在测试模式下为端口 8081)。这些事件将直接放置在 Quarkus Lambda 轮询循环上进行处理。以下是一个示例:

If you want to simulate more complex API Gateway events in your tests, then manually do an HTTP POST to http://localhost:8080/lambda (port 8081 in test mode) with the raw API Gateway json events. These events will be placed directly on the Quarkus Lambda poll loop for processing. Here’s an example of that:

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.equalTo;

import com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent;

import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class AmazonLambdaSimpleTestCase {
    @Test
    public void testJaxrsCognitoJWTSecurityContext() throws Exception {
        APIGatewayV2HTTPEvent request = request("/security/username");
        request.getRequestContext().setAuthorizer(new APIGatewayV2HTTPEvent.RequestContext.Authorizer());
        request.getRequestContext().getAuthorizer().setJwt(new APIGatewayV2HTTPEvent.RequestContext.Authorizer.JWT());
        request.getRequestContext().getAuthorizer().getJwt().setClaims(new HashMap<>());
        request.getRequestContext().getAuthorizer().getJwt().getClaims().put("cognito:username", "Bill");

        given()
                .contentType("application/json")
                .accept("application/json")
                .body(request)
                .when()
                .post("/_lambda_")
                .then()
                .statusCode(200)
                .body("body", equalTo("Bill"));
    }

以上示例模拟使用 HTTP 请求向你的 HTTP Lambda 发送 Cognito 主体。

The above example simulates sending a Cognito principal with an HTTP request to your HTTP Lambda.

如果你想为 AWS HTTP API 手动编写原始事件,AWS Lambda 库有请求事件类型为 com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent ,响应事件类型为 com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPResponse 。这对应于 quarkus-amazon-lambda-http 扩展和 AWS HTTP API。

If you want to hand code raw events for the AWS HTTP API, the AWS Lambda library has the request event type which is com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent and the response event type of com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPResponse. This corresponds to the quarkus-amazon-lambda-http extension and the AWS HTTP API.

如果您想为 AWS REST API 手动编写原始事件,Quarkus 有自己的实现:io.quarkus.amazon.lambda.http.model.AwsProxyRequestio.quarkus.amazon.lambda.http.model.AwsProxyResponse。这对应于 quarkus-amazon-lambda-rest 扩展和 AWS REST API。

If you want to hand code raw events for the AWS REST API, Quarkus has its own implementation: io.quarkus.amazon.lambda.http.model.AwsProxyRequest and io.quarkus.amazon.lambda.http.model.AwsProxyResponse. This corresponds to quarkus-amazon-lambda-rest extension and the AWS REST API.

模拟事件服务器还为 @QuarkusIntegrationTest 测试启动,因此也将适用于原生二进制文件。所有这些都提供了类似于 SAM CLI 本地测试的功能,但无需 Docker 的开销。

The mock event server is also started for @QuarkusIntegrationTest tests so will work with native binaries too. All this provides similar functionality to the SAM CLI local testing, without the overhead of Docker.

最后,如果计算机上没有端口 8080 或端口 8081,您可以使用 application.properties 修改开发和测试模式端口

Finally, if port 8080 or port 8081 is not available on your computer, you can modify the dev and test mode ports with application.properties

quarkus.lambda.mock-event-server.dev-port=8082
quarkus.lambda.mock-event-server.test-port=8083

端口值为零将导致随机分配端口。

A port value of zero will result in a randomly assigned port.

关闭模拟事件服务器:

To turn off the mock event server:

quarkus.lambda.mock-event-server.enabled=false

Simulate AWS Lambda Deployment with SAM CLI

AWS SAM CLI 允许您在模拟的 Lambda 环境中在笔记本电脑上本地运行 lambda。这需要安装 Docker。构建 Maven 项目后,执行此命令:

The AWS SAM CLI allows you to run your lambda’s locally on your laptop in a simulated Lambda environment. This requires Docker to be installed. After you have built your Maven project, execute this command:

sam local start-api --template target/sam.jvm.yaml

这将启动一个模仿亚马逊 Lambda 部署环境的 Docker 容器。环境启动后,您可以通过转到以下位置在浏览器中调用示例 lambda:

This will start a Docker container that mimics Amazon’s Lambda’s deployment environment. Once the environment is started you can invoke the example lambda in your browser by going to:

[role="bare"][role="bare"]http://127.0.0.1:3000/hello

在控制台中,您将看到来自 lambda 的启动消息。此特定部署启动了 JVM 并将您的 lambda 加载为纯 Java。

In the console you’ll see startup messages from the lambda. This particular deployment starts a JVM and loads your lambda as pure Java.

Deploy to AWS

sam deploy -t target/sam.jvm.yaml -g

回答所有问题,您的 lambda 将被部署,并且将建立与 API Gateway 的必要挂钩。如果一切部署成功,您的微服务的根 URL 将输出到控制台。类似以下内容:

Answer all the questions and your lambda will be deployed and the necessary hooks to the API Gateway will be set up. If everything deploys successfully, the root URL of your microservice will be output to the console. Something like this:

Key                 LambdaHttpApi
Description         URL for application
Value               https://234asdf234as.execute-api.us-east-1.amazonaws.com/

Value 属性是 lambda 的根 URL。将其复制到您的浏览器并在末尾添加 hello

The Value attribute is the root URL for your lambda. Copy it to your browser and add hello at the end.

二进制类型的响应将自动使用 base64 编码。这与使用 quarkus:dev 的行为不同,它将返回原始字节。亚马逊的 API 要求进行 base64 编码,还有其他限制。通常情况下,客户端代码将自动处理此编码,但在某些自定义情况下,您应该知道您可能需要手动管理该编码。

Responses for binary types will be automatically encoded with base64. This is different from the behavior using quarkus:dev which will return the raw bytes. Amazon’s API has additional restrictions requiring the base64 encoding. In general, client code will automatically handle this encoding but in certain custom situations, you should be aware you may need to manually manage that encoding.

Deploying a native executable

要部署原生可执行文件,您必须使用 GraalVM 构建它。

To deploy a native executable, you must build it with GraalVM.

Unresolved directive in aws-lambda-http.adoc - include::{includes}/devtools/build-native-container.adoc[]

然后,您可以使用 sam local 在本地测试可执行文件

You can then test the executable locally with sam local

sam local start-api --template target/sam.native.yaml

要部署到 AWS Lambda:

To deploy to AWS Lambda:

sam deploy -t target/sam.native.yaml -g

Examine the POM

POM 没有什么特别的,除了包含 quarkus-amazon-lambda-http 扩展(如果您要部署 AWS Gateway HTTP API)或 quarkus-amazon-lambda-rest 扩展(如果您要部署 AWS Gateway REST API)。这些扩展会自动生成 lambda 部署所需的一切。

There is nothing special about the POM other than the inclusion of the quarkus-amazon-lambda-http extension (if you are deploying an AWS Gateway HTTP API) or the quarkus-amazon-lambda-rest extension (if you are deploying an AWS Gateway REST API). These extensions automatically generate everything you might need for your lambda deployment.

此外,至少在生成的 Maven 典型文件 pom.xml 中,quarkus-restquarkus-reactive-routesquarkus-undertow 依赖项都是可选的。选择您要使用的 HTTP 框架(Jakarta REST、Reactive Routes 和/或 Servlet)并删除其他依赖项以缩小部署大小。

Also, at least in the generated Maven archetype pom.xml, the quarkus-rest, quarkus-reactive-routes, and quarkus-undertow dependencies are all optional. Pick which HTTP framework(s) you want to use (Jakarta REST, Reactive Routes, and/or Servlet) and remove the other dependencies to shrink your deployment.

Examine sam.yaml

sam.yaml 语法超出了本文档的范围。如果您打算制作自己的自定义 sam.yaml 部署文件,则必须重点强调几件事。

The sam.yaml syntax is beyond the scope of this document. There’s a couple of things that must be highlighted just in case you are going to craft your own custom sam.yaml deployment files.

首先要注意的是,对于纯 Java lambda 部署,需要一个特定的处理程序类。不要更改 Lambda 处理程序的名称。

The first thing to note is that for pure Java lambda deployments require a specific handler class. Do not change the Lambda handler name.

     Properties:
        Handler: io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest
        Runtime: java17

该句柄是 Lambda 运行时和您正在使用的 Quarkus HTTP 框架(Jakarta REST、Servlet 等)之间的桥梁。

This handler is a bridge between the lambda runtime and the Quarkus HTTP framework you are using (Jakarta REST, Servlet, etc.)

如果您想进行本机化部署,则需要为本机 GraalVM 部署设置一个环境变量。如果您查看 sam.native.yaml,您会看到以下内容:

If you want to go native, there’s an environment variable that must be set for native GraalVM deployments. If you look at sam.native.yaml you’ll see this:

        Environment:
          Variables:
            DISABLE_SIGNAL_HANDLERS: true

此环境变量解决了 Quarkus 和 AWS Lambda 自定义运行时环境之间的一些不兼容性。

This environment variable resolves some incompatibilities between Quarkus and the AWS Lambda Custom Runtime environment.

最后,对于 AWS Gateway REST API 部署还有一项特殊设置。该 API 假定 HTTP 响应主体为文本,除非您通过配置明确告诉它哪些媒体类型是二进制的。为了简化操作,Quarkus 扩展会强制对所有 HTTP 响应消息进行二进制(base 64)编码,并且 sam.yaml 文件必须配置 API Gateway 以假定所有媒体类型都是二进制的:

Finally, there is one specific thing for AWS Gateway REST API deployments. That API assumes that HTTP response bodies are text unless you explicitly tell it which media types are binary through configuration. To make things easier, the Quarkus extension forces a binary (base 64) encoding of all HTTP response messages and the sam.yaml file must configure the API Gateway to assume all media types are binary:

  Globals:
    Api:
      EndpointConfiguration: REGIONAL
      BinaryMediaTypes:
        - "*/*"

Injectable AWS Context Variables

如果您正在使用 Quarkus REST 和 Jakarta REST,您可以使用 Jakarta REST @Context 注释或带有 CDI @Inject 注释的其他任何位置将各种 AWS 上下文变量注入到 Jakarta REST 资源类。

If you are using Quarkus REST and Jakarta REST, you can inject various AWS Context variables into your Jakarta REST resource classes using the Jakarta REST @Context annotation or anywhere else with the CDI @Inject annotation.

对于 AWS HTTP API,您可以注入 AWS 变量 com.amazonaws.services.lambda.runtime.Contextcom.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent。以下是一个示例:

For the AWS HTTP API you can inject the AWS variables com.amazonaws.services.lambda.runtime.Context and com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent. Here is an example:

import jakarta.ws.rs.core.Context;
import com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent;


@Path("/myresource")
public class MyResource {
    @GET
    public String ctx(@Context com.amazonaws.services.lambda.runtime.Context ctx) { }

    @GET
    public String event(@Context APIGatewayV2HTTPEvent event) { }

    @GET
    public String requestContext(@Context APIGatewayV2HTTPEvent.RequestContext req) { }


}

对于 AWS REST API,您可以注入 AWS 变量 com.amazonaws.services.lambda.runtime.Contextio.quarkus.amazon.lambda.http.model.AwsProxyRequestContext。以下是一个示例:

For the AWS REST API you can inject the AWS variables com.amazonaws.services.lambda.runtime.Context and io.quarkus.amazon.lambda.http.model.AwsProxyRequestContext. Here is an example:

import jakarta.ws.rs.core.Context;
import io.quarkus.amazon.lambda.http.model.AwsProxyRequestContext;
import io.quarkus.amazon.lambda.http.model.AwsProxyRequest;


@Path("/myresource")
public class MyResource {
    @GET
    public String ctx(@Context com.amazonaws.services.lambda.runtime.Context ctx) { }

    @GET
    public String reqContext(@Context AwsProxyRequestContext req) { }

    @GET
    public String req(@Context AwsProxyRequest req) { }

}

Tracing with AWS XRay and GraalVM

如果您正在构建本机镜像,并且希望在 lambda 中使用 AWS X-Ray Tracing,您需要将 quarkus-amazon-lambda-xray 包含到 pom 中作为依赖项。AWS X-Ray 库与 GraalVM 并不完全兼容,因此我们必须做一些集成工作才能使其正常运行。

If you are building native images, and want to use AWS X-Ray Tracing with your lambda you will need to include quarkus-amazon-lambda-xray as a dependency in your pom. The AWS X-Ray library is not fully compatible with GraalVM, so we had to do some integration work to make this work.

Security Integration

当您在 API Gateway 上调用一个 HTTP 请求时,Gateway 会将该 HTTP 请求转换为 JSON 事件文档,并将其转发到 Quarkus Lambda。Quarkus Lambda 会解析此 json 并将其转换为内部 HTTP 请求表示,任何 Quarkus 支持的 HTTP 框架(Jakarta REST、servlet、Reactive Routes)均可使用该表示。

When you invoke an HTTP request on the API Gateway, the Gateway turns that HTTP request into a JSON event document that is forwarded to a Quarkus Lambda. The Quarkus Lambda parses this json and converts in into an internal representation of an HTTP request that can be consumed by any HTTP framework Quarkus supports (Jakarta REST, servlet, Reactive Routes).

API Gateway 支持多种安全方式来调用由 Lambda 和 Quarkus 支持的 HTTP 端点。如果您启用它,Quarkus 将自动解析 event json document 的相关部分并查找基于安全性的元数据,并在内部注册一个 java.security.Principal,它可以通过在 Jakarta REST 中注入一个 jakarta.ws.rs.core.SecurityContext、在 servlet 中通过 HttpServletRequest.getUserPrincipal() 和在 Reactive Routes 中通过 RouteContext.user() 来查找。如果您想要更多安全信息,可以将 Principal 对象强制转换为一个类,该类将为您提供更多信息。

API Gateway supports many ways to securely invoke on your HTTP endpoints that are backed by Lambda and Quarkus. If you enable it, Quarkus will automatically parse relevant parts of the event json document and look for security based metadata and register a java.security.Principal internally that can be looked up in Jakarta REST by injecting a jakarta.ws.rs.core.SecurityContext, via HttpServletRequest.getUserPrincipal() in servlet, and RouteContext.user() in Reactive Routes. If you want more security information, the Principal object can be typecast to a class that will give you more information.

要启用此安全功能,请将以下内容添加到您的 application.properties 文件:

To enable this security feature, add this to your application.properties file:

quarkus.lambda-http.enable-security=true

以下是它的映射方式:

Here’s how its mapped:

Table 1. HTTP quarkus-amazon-lambda-http
Auth Type Principal Class Json path of Principal Name

Cognito JWT

io.quarkus.amazon.lambda.http.CognitoPrincipal

requestContext.authorizer.jwt.claims.cognito:username

IAM

io.quarkus.amazon.lambda.http.IAMPrincipal

requestContext.authorizer.iam.userId

Custom Lambda

io.quarkus.amazon.lambda.http.CustomPrincipal

requestContext.authorizer.lambda.principalId

Table 2. REST quarkus-amazon-lambda-rest
Auth Type Principal Class Json path of Principal Name

Cognito

io.quarkus.amazon.lambda.http.CognitoPrincipal

requestContext.authorizer.claims.cognito:username

IAM

io.quarkus.amazon.lambda.http.IAMPrincipal

requestContext.identity.user

Custom Lambda

io.quarkus.amazon.lambda.http.CustomPrincipal

requestContext.authorizer.principalId

如果 cognito:groups 声明存在,那么 Quarkus 将提取并映射这些组到 Quarkus 角色,然后可在授权中使用它们,如“@RolesAllowed”注释。如果您不希望将 cognito:groups 映射到 Quarkus 角色,那么您必须在配置中明确禁用它:

If the cognito:groups claim is present, then Quarkus will extract and map those groups to Quarkus roles which can then be used in authorization with annotations like @RolesAllowed. If you do not want to map cognito:groups to Quarkus roles, then you must explicitly disable it in configuration:

quarkus.lambda-http.map-cognito-to-roles=false

您还可以指定提取角色的不同 Cognito 声明:

You can also specify a different Cognito claim to extract roles from:

quarkus.lambda-http.cognito-role-claim=cognito:roles

默认情况下,它会查找用括号括起来的空格分隔列表中的角色,即 [ user admin ]。您还可以指定正则表达式,以查找声明字符串中的各个角色:

By default, it expects roles in a space delimited list enclosed in brackets i.e. [ user admin ]. You can specify the regular expression to use to find individual roles in the claim string too:

quarkus.lambda-http.cognito-claim-matcher=[^\[\] \t]+

Custom Security Integration

对 AWS 安全的默认支持只会将主体名称映射到 Quarkus Security API,而不会对声明、角色或权限进行任何映射。您可以使用 io.quarkus.amazon.lambda.http.LambdaIdentityProvider 界面实现来完全控制 lambda HTTP 事件中的安全元数据如何映射到 Quarkus Security API。通过实现此界面,您可以执行操作,例如为您的主体定义角色映射,或发布由 IAM 或 Cognito 或您的自定义 Lambda 安全集成提供的其他属性。

The default support for AWS security only maps the principal name to Quarkus security APIs and does nothing to map claims or roles or permissions. You have full control on how security metadata in the lambda HTTP event is mapped to Quarkus Security APIs using implementations of the io.quarkus.amazon.lambda.http.LambdaIdentityProvider interface. By implementing this interface, you can do things like define role mappings for your principal or publish additional attributes provided by IAM or Cognito or your Custom Lambda security integration.

HTTP quarkus-amazon-lambda-http
package io.quarkus.amazon.lambda.http;

/**
 * Helper interface that removes some boilerplate for creating
 * an IdentityProvider that processes APIGatewayV2HTTPEvent
 */
public interface LambdaIdentityProvider extends IdentityProvider<LambdaAuthenticationRequest> {
    @Override
    default public Class<LambdaAuthenticationRequest> getRequestType() {
        return LambdaAuthenticationRequest.class;
    }

    @Override
    default Uni<SecurityIdentity> authenticate(LambdaAuthenticationRequest request, AuthenticationRequestContext context) {
        APIGatewayV2HTTPEvent event = request.getEvent();
        SecurityIdentity identity = authenticate(event);
        if (identity == null) {
            return Uni.createFrom().optional(Optional.empty());
        }
        return Uni.createFrom().item(identity);
    }

    /**
     * You must override this method unless you directly override
     * IdentityProvider.authenticate
     *
     * @param event
     * @return
     */
    default SecurityIdentity authenticate(APIGatewayV2HTTPEvent event) {
        throw new IllegalStateException("You must override this method or IdentityProvider.authenticate");
    }
}

对于 HTTP,要覆盖的重要方法是 LambdaIdentityProvider.authenticate(APIGatewayV2HTTPEvent event)。在此基础上,您将根据希望如何从 APIGatewayV2HTTPEvent 映射安全数据来分配一个 SecurityIdentity。

For HTTP, the important method to override is LambdaIdentityProvider.authenticate(APIGatewayV2HTTPEvent event). From this you will allocate a SecurityIdentity based on how you want to map security data from APIGatewayV2HTTPEvent

REST quarkus-amazon-lambda-rest
package io.quarkus.amazon.lambda.http;

import java.util.Optional;

import com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent;

import io.quarkus.amazon.lambda.http.model.AwsProxyRequest;
import io.quarkus.security.identity.AuthenticationRequestContext;
import io.quarkus.security.identity.IdentityProvider;
import io.quarkus.security.identity.SecurityIdentity;
import io.smallrye.mutiny.Uni;

/**
 * Helper interface that removes some boilerplate for creating
 * an IdentityProvider that processes APIGatewayV2HTTPEvent
 */
public interface LambdaIdentityProvider extends IdentityProvider<LambdaAuthenticationRequest> {
...

    /**
     * You must override this method unless you directly override
     * IdentityProvider.authenticate
     *
     * @param event
     * @return
     */
    default SecurityIdentity authenticate(AwsProxyRequest event) {
        throw new IllegalStateException("You must override this method or IdentityProvider.authenticate");
    }
}

对于 REST,要覆盖的重要方法是 LambdaIdentityProvider.authenticate(AwsProxyRequest event)。在此基础上,您将根据希望如何从 AwsProxyRequest 映射安全数据来分配一个 SecurityIdentity。

For REST, the important method to override is LambdaIdentityProvider.authenticate(AwsProxyRequest event). From this you will allocate a SecurityIdentity based on how you want to map security data from AwsProxyRequest.

您实现的提供程序必须是 CDI Bean。以下是一个示例:

Your implemented provider must be a CDI bean. Here’s an example:

package org.acme;

import java.security.Principal;

import jakarta.enterprise.context.ApplicationScoped;

import com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent;

import io.quarkus.amazon.lambda.http.LambdaIdentityProvider;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.runtime.QuarkusPrincipal;
import io.quarkus.security.runtime.QuarkusSecurityIdentity;

@ApplicationScoped
public class CustomSecurityProvider implements LambdaIdentityProvider {
    @Override
    public SecurityIdentity authenticate(APIGatewayV2HTTPEvent event) {
        if (event.getHeaders() == null || !event.getHeaders().containsKey("x-user"))
            return null;
        Principal principal = new QuarkusPrincipal(event.getHeaders().get("x-user"));
        QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder();
        builder.setPrincipal(principal);
        return builder.build();
    }
}

以下是相同的示例,但使用 AWS Gateway REST API:

Here’s the same example, but with the AWS Gateway REST API:

package org.acme;

import java.security.Principal;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.amazon.lambda.http.model.AwsProxyRequest;

import io.quarkus.amazon.lambda.http.LambdaIdentityProvider;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.runtime.QuarkusPrincipal;
import io.quarkus.security.runtime.QuarkusSecurityIdentity;

@ApplicationScoped
public class CustomSecurityProvider implements LambdaIdentityProvider {
    @Override
    public SecurityIdentity authenticate(AwsProxyRequest event) {
        if (event.getMultiValueHeaders() == null || !event.getMultiValueHeaders().containsKey("x-user"))
            return null;
        Principal principal = new QuarkusPrincipal(event.getMultiValueHeaders().getFirst("x-user"));
        QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder();
        builder.setPrincipal(principal);
        return builder.build();
    }
}

Quarkus 应该自动发现此实现并使用它,而不是前面讨论的默认实现。

Quarkus should automatically discover this implementation and use it instead of the default implementation discussed earlier.

Simple SAM Local Principal

如果使用 sam local 测试应用程序,可以通过设置 QUARKUS_AWS_LAMBDA_FORCE_USER_NAME 环境变量来硬编码应用程序运行时要使用的主体名称。

If you are testing your application with sam local you can hardcode a principal name to use when your application runs by setting the QUARKUS_AWS_LAMBDA_FORCE_USER_NAME environment variable

SnapStart

要针对 Lambda SnapStart 优化您的应用程序,请查看 the SnapStart Configuration Documentation

To optimize your application for Lambda SnapStart, check the SnapStart Configuration Documentation.