Как получить данные 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();