Как получить данные requestContext в реализации API Micronaut, являющейся частью прокси-сервера AWS Lambda

В прокси-сервере AWS Lambda (являющемся интеграцией в шлюз API, который использует авторизацию Cognito) я хотел бы получить идентификатор пользователя при обработке запроса. Лямбда написана на Java с использованием Micronaut. Одна и та же Lambda используется как интеграция нескольких конечных точек API.

Я обнаружил, что идентификатор пользователя Cognito содержится в записи requestContext прокси-данных, переданных обработчику Lambda:

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);
    }
}

При вызове Lambda через API при аутентификации как пользователя Cognito input Steam выглядит так (некоторые детали опущены / изменены на примерные значения, а идентификатор пользователя Cognito отмечен // !!!):

{
    "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 делает многое за кулисами, что я еще не полностью понимаю; однако, в конце концов, я могу определять конечные точки API, используя аннотации micronaut в классе контроллера:

@Controller("/")
public class TestController {

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

}

Этот пример - обработчик запроса для GET /test.

Объект HttpRequest содержит все из исходного запроса, например заголовки и прочее, но не информацию, которую шлюз AWS добавляет к этому, например результат аутентификации.

Как я могу теперь получить доступ к этому, в частности к requestContext, который был передан Lambda через его ввод? Я здесь упускаю какую-то часть головоломки.

1 ответ

Решение

Micronaut определяет две типизированные папки, называемые AwsProxyRequestArgumentBinder а также ContextArgumentBinder. В соответствии с документацией, связанные с типом параметры могут быть запрошены в аргументах метода по их типу.

Итак, вы сможете использовать одно из них:

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();
Другие вопросы по тегам