如何在作为 AWS Lambda 代理一部分的 Micronaut API 实施中获取"requestContext"数据



在 AWS Lambda 代理(使用 Cognito 授权的 API 网关中的集成(中,我想在处理请求时获取用户 ID。Lambda是使用Micronaut用Java编写的。相同的 Lambda 用作多个 API 终端节点的集成。

我发现 Cognito 用户 ID 包含在提供给 Lambda 处理程序的代理数据的 requestContext 条目中:

public class Handler implements RequestStreamHandler {
private static MicronautLambdaContainerHandler handler = new MicronautLambdaContainerHandler();
@Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
// `input` contains the information I need (see below)
handler.proxyStream(input, output, context);
}
}

在以 Cognito 用户身份进行身份验证时通过 API 调用 Lambda 时,inputSteam 如下所示(一些细节省略/更改为示例值,并且 Cognito 用户 ID 标记为// !!!(:

{
"resource": "/test",
"path": "/test",
"httpMethod": "GET",
"headers": {
"accept": "application/json, text/plain, */*",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.5",
"Authorization": "Bearer eyJraWQiOiJPWlgzYVg3UWNITFwvM09vODg4SzhaYjBlcmRJMjZNNWFRdXF3a3VyZWhaVT0iLCJhbGciOiJSUzI1NiJ9[...]",
"cache-control": "no-cache",
"Host": "api.my-app.example.com",
"origin": "https://my-app.example.com",
"pragma": "no-cache",
"referer": "https://my-app.example.com/home",
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0",
"X-Amzn-Trace-Id": "Root=1-5ebbd0f0-[...]",
"X-Forwarded-For": "[...]",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"multiValueHeaders": {
/* similar to above but values being arrays */
},
"queryStringParameters": null,
"multiValueQueryStringParameters": null,
"pathParameters": {},
"stageVariables": null,
"requestContext": {
"resourceId": "927cr8",
"authorizer": {
"claims": {
"sub": "c99202cc-e088-43d6-8c15-1fd73a717a7c",    // !!!
"cognito:groups": "[...]",
"iss": "https://cognito-idp.eu-central-1.amazonaws.com/eu-central-1_[...]",
"cognito:username": "c99202cc-e088-43d6-8c15-1fd73a717a7c",    // !!!
"aud": "[...]",
"event_id": "0d509360-d81e-4e7e-b346-9d018ed1cd04",
"token_use": "id",
"custom:[...]": "[...]",
"auth_time": "1587536524",
"name": "[...]",
"exp": "Wed May 13 11:45:53 UTC 2020",
"iat": "Wed May 13 10:45:53 UTC 2020",
"email": "[...]"
}
},
"resourcePath": "/test",
"httpMethod": "GET",
"extendedRequestId": "Md2VmF0OFiAFhZA=",
"requestTime": "13/May/2020:10:50:24 +0000",
"path": "/test",
"accountId": "[...]",
"protocol": "HTTP/1.1",
"stage": "default",
"domainPrefix": "api",
"requestTimeEpoch": 1589367024516,
"requestId": "feb2c8b2-4cf6-405b-bc48-76ebe33fde62",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"sourceIp": "[...]",
"principalOrgId": null,
"accessKey": null,
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0",
"user": null
},
"domainName": "api.my-app.example.com",
"apiId": "[...]"
},
"body": null,
"isBase64Encoded": false
}

然后,MicronautLambdaContainerHandler在幕后做了很多我还没有完全理解的事情;但是,最终我能够在控制器类中使用micronaut的注释来定义API端点:

@Controller("/")
public class TestController {
@Get("/test")
public HttpResponse<String> test(HttpRequest<?> request) {
String userId = ?
}
}

此示例是GET /test的请求处理程序。

HttpRequest 对象包含原始请求中的所有内容,如标头和其他内容,但不包含 AWS 网关向其添加的信息,例如身份验证结果。

我现在如何访问它,特别是通过其输入传递给 Lambda 的请求上下文?我在这里错过了一些拼图。

Micronaut定义了两个类型化的粘合剂,称为AwsProxyRequestArgumentBinderContextArgumentBinder。根据文档,类型绑定参数可以按其类型在方法参数中请求。

因此,您应该能够使用以下之一:

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
@Controller("/")
public class TestController {
@Get("/test")
public HttpResponse<String> test(HttpRequest<?> request, Context context) {
String userId = context.getAuthorizer().getClaims().getSubject();
}
@Get("/test")
public HttpResponse<String> test2(HttpRequest<?> request, AwsProxyRequest awsRequest) {
String userId = awsRequest.getRequestContext().getAuthorizer().getClaims().getSubject();
}
}

如果这不起作用,也许只是从它们的源代码中复制这两个绑定器的作用。

source.getAttribute(RequestReader.LAMBDA_CONTEXT_PROPERTY);

或:

((MicronautAwsProxyRequest<?>) source).getAwsProxyRequest();

最新更新