Я использую в своей архитектуре функции Cognito, API Gateway и Lambda.
На клиенте я использую AWS Amplify.API, чтобы сделать запрос, и запрос авторизуется Cognito, как только он попадает в API Gateway . Если запрос авторизован, он передается в функцию Lambda, где мне нужно иметь доступ к вошедшему в систему пользователю, который делает запрос, чтобы иметь возможность запускать мой бизнес-журнал c.
В контексте функции Lambda у меня есть доступ к некоторым переменным среды, CognitoUserPoolId
одна из них.
У меня также есть доступ к любому запросу, переданному через API, живущему в event
.
{
"tok": {
"resource": "/some_resource",
"path": "/some_resource",
"httpMethod": "GET",
"headers": {
"Accept": "application/json",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-GB,en;q=0.9,sv;q=0.8,en-US;q=0.7,el;q=0.6,de;q=0.5,el-GR;q=0.4",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "SE",
"content-type": "application/json",
"Host": "XXXXXX.execute-api.eu-central-1.amazonaws.com",
"origin": "http://localhost:8080",
"Referer": "http://localhost:8080/some_resource",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "cross-site",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
"Via": "2.0 XXXXXXXXXXXX.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "XXXXXXXXXXXXXXXXXXXXXXXXTelrg==",
"x-amz-date": "20200527T233945Z",
"x-amz-security-token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX8fR",
"X-Amzn-Trace-Id": "Root=1-5XXXXa41-730XXXXXXXXXXabe42f1",
"X-Forwarded-For": "XXX.XXX.XX.XXX, XXX.XXX.XXX.XXX",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"multiValueHeaders": {
"Accept": [
"application/json"
],
"Accept-Encoding": [
"gzip, deflate, br"
],
"Accept-Language": [
"en-GB,en;q=0.9,sv;q=0.8,en-US;q=0.7,el;q=0.6,de;q=0.5,el-GR;q=0.4"
],
"CloudFront-Forwarded-Proto": [
"https"
],
"CloudFront-Is-Desktop-Viewer": [
"true"
],
"CloudFront-Is-Mobile-Viewer": [
"false"
],
"CloudFront-Is-SmartTV-Viewer": [
"false"
],
"CloudFront-Is-Tablet-Viewer": [
"false"
],
"CloudFront-Viewer-Country": [
"SE"
],
"content-type": [
"application/json"
],
"Host": [
"XXXXXX.execute-api.eu-central-1.amazonaws.com"
],
"origin": [
"http://localhost:8080"
],
"Referer": [
"http://localhost:8080/some_resource"
],
"sec-fetch-dest": [
"empty"
],
"sec-fetch-mode": [
"cors"
],
"sec-fetch-site": [
"cross-site"
],
"User-Agent": [
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
],
"Via": [
"2.0 XXXXXXXXXXXX.cloudfront.net (CloudFront)"
],
"X-Amz-Cf-Id": [
"XXXXXXXXXXXXXXXXXXXXXXXXTelrg=="
],
"x-amz-date": [
"20200527T233945Z"
],
"x-amz-security-token": [
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX8fR"
],
"X-Amzn-Trace-Id": [
"Root=1-5XXXXa41-730XXXXXXXXXXabe42f1"
],
"X-Forwarded-For": [
"XXX.XXX.XX.XXX, XXX.XXX.XXX.XXX"
],
"X-Forwarded-Port": [
"443"
],
"X-Forwarded-Proto": [
"https"
]
},
"queryStringParameters": null,
"multiValueQueryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"resourceId": "5qXXXXXXX",
"resourcePath": "/some_resource",
"httpMethod": "GET",
"extendedRequestId": "NNwKXXXXXXXXX=",
"requestTime": "27/May/2020:23:39:45 +0000",
"path": "/dev/some_resource",
"accountId": "18XXXXXXXX",
"protocol": "HTTP/1.1",
"stage": "dev",
"domainPrefix": "XXXXXX",
"requestTimeEpoch": 1590622785474,
"requestId": "XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX",
"identity": {
"cognitoIdentityPoolId": "eu-central-1:XXXXXX-YYY-YYYY-YYYY-YYYYY",
"accountId": "181606720624",
"cognitoIdentityId": "eu-central-1:XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX",
"caller": "SOME_STRING_HERE:CognitoIdentityCredentials",
"sourceIp": "XXX.XXX.XXX.XXX",
"principalOrgId": null,
"accessKey": "ACCESS_KEY_HERE",
"cognitoAuthenticationType": "authenticated",
"cognitoAuthenticationProvider": "cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XXXXXX,cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XXXXXX:CognitoSignIn:XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX",
"userArn": "arn:aws:sts::XXXXXX:assumed-role/amplify-XXXXXX-dev-XXXXXX-authRole/CognitoIdentityCredentials",
"userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
"user": "SOME_STRING_HERE:CognitoIdentityCredentials"
},
"domainName": "XXXXXX.execute-api.eu-central-1.amazonaws.com",
"apiId": "XXXXXX"
},
"body": null,
"isBase64Encoded": false
}
}
Имея под рукой всю эту информацию, как я могу получить доступ к пользовательским атрибутам пользователя, который сделал запрос?
Я изучал: Boto3 CognitoIdentityProvider.get_user () и Boto3 CognitoIdentityProvider.admin_get_user () , однако для обоих требуется либо AccessToken
, либо userId
, и ни один из них не доступен в контексте функции Lambda. Единственный способ, который я придумал, - это передать некоторую дополнительную информацию в полезных данных запроса, но на самом деле это не кажется лучшим способом получить атрибуты пользователя.
EDIT
Я не использую специальный авторизатор в API. При настройке API с помощью Amplify я выбрал защищенные пути, и все запросы аутентифицируются / авторизуются в пуле пользователей Cognito. После amplify push
я вижу, что развернутый API имеет AWS_IAM
под Auth
в запросе метода для всех ресурсов.
Amplify.API.get
при выполнении запроса включает заголовки для авторизации, а точнее:
:authority: XXXXXX.execute-api.eu-central-1.amazonaws.com
:method: GET
:path: /dev/some_resource
:scheme: https
accept: application/json
accept-encoding: gzip, deflate, br
accept-language: en-GB,en;q=0.9,sv;q=0.8,en-US;q=0.7,el;q=0.6,de;q=0.5,el-GR;q=0.4
authorization: AWS4-HMAC-SHA256 Credential=ASIAXXXXXXXX/20200528/eu-central-1/execute-api/aws4_request, SignedHeaders=accept;content-type;host;x-amz-date;x-amz-security-token, Signature=b6a7aXXX1c447bXXX...XXX
content-type: application/json
origin: http://localhost:8080
referer: http://localhost:8080/dashboard
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36
x-amz-date: 20200528T075958Z
x-amz-security-token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...XXXXXXXXXX
Ресурс API интегрирован в лямбда-функцию с интеграцией лямбда-прокси. Я вижу, что вызывается функция Lambda, поэтому запрос разрешен правильно. Однако все, что у меня есть в event
в Lambda, - это то, что я вставил в первый клип выше.
Учитывая, что это интеграция с прокси, я ожидаю, что все, что находится в контексте в API, должно будут перенаправлены в Lambda за API. Однако я не вижу, как получить доступ к атрибутам user_attributes с помощью какой-либо информации, доступной в Lambda. Любые указатели?
EDIT 2
Сейчас я изучаю возможность передачи пользовательских данных от клиента с использованием настраиваемых заголовков, возможно, что-то вроде:
'x-user-sub': '58ce94f6-53vd-4s3e-b088-cd6f85s0ff43'
, а затем используйте приведенную ниже функцию в моей лямбда-функции, чтобы получить атрибуты пользователя:
c_client = boto3.client('cognito-idp')
response = c_client.admin_get_user(
UserPoolId='eu-central-1_XXXXXX',
Username='58ce94f6-53vd-4s3e-b088-cd6f85s0ff43'
)
Вышеуказанное возвращает:
{
'Username': '58ce94f6-53vd-4s3e-b088-cd6f85s0ff43',
'UserAttributes': [
{
'Name': 'sub',
'Value': '58ce94f6-53vd-4s3e-b088-cd6f85s0ff43'
},
{
'Name': 'email_verified',
'Value': 'true'
},
{
'Name': 'phone_number_verified',
'Value': 'true'
},
{
'Name': 'phone_number',
'Value': '+46XXXXXXXXXX'
},
{
'Name': 'email',
'Value': 'XXXXXX.XXXXX@YYYY.com'
}
],
'UserCreateDate': datetime.datetime(2020, 5, 14, 15, 43, 3, 370000, tzinfo=tzlocal()),
'UserLastModifiedDate': datetime.datetime(2020, 5, 15, 16, 32, 43, 424000, tzinfo=tzlocal()),
'Enabled': true,
'UserStatus': 'CONFIRMED',
'ResponseMetadata': {
'RequestId': 'e441edd4-XXX-46ba-XXX-922691471f2c',
'HTTPStatusCode': 200,
'HTTPHeaders': {
'date': 'Thu, 28 May 2020 12:58:18 GMT',
'content-type': 'application/x-amz-json-1.1',
'content-length': '431',
'connection': 'keep-alive',
'x-amzn-requestid': 'e441edd4-XXX-46ba-XXX-922691471f2c'
},
'RetryAttempts': 0
}
}
Есть ли что-нибудь очевидное, что я отсутствует с этим решением? Вношу ли я какие-либо риски безопасности, передавая sub
в заголовке клиента?
Любая помощь очень ценится.