Amazon web services 从Lambda中访问cognito用户属性

Amazon web services 从Lambda中访问cognito用户属性,amazon-web-services,aws-lambda,aws-api-gateway,amazon-cognito,aws-amplify-cli,Amazon Web Services,Aws Lambda,Aws Api Gateway,Amazon Cognito,Aws Amplify Cli,我在我的体系结构中使用Cognito、API网关和Lambda函数 在客户机上,我使用AWS Amplify.API发出请求,该请求在到达API网关后由Cognito授权。如果请求得到授权,它将传递到Lambda函数,在该函数中,我需要访问发出请求的登录用户,以便能够运行我的业务逻辑 在Lambda函数的上下文中,我可以访问一些环境变量,CognitoUserPoolId就是其中之一 我还可以访问通过API传递的任何请求,它们位于事件中 { "tok": { "resource":

我在我的体系结构中使用Cognito、API网关和Lambda函数

在客户机上,我使用AWS Amplify.API发出请求,该请求在到达API网关后由Cognito授权。如果请求得到授权,它将传递到Lambda函数,在该函数中,我需要访问发出请求的登录用户,以便能够运行我的业务逻辑

在Lambda函数的上下文中,我可以访问一些环境变量,
CognitoUserPoolId
就是其中之一

我还可以访问通过API传递的任何请求,它们位于
事件中

{
  "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
  }
}
有了所有这些信息,我如何访问发出请求的用户的用户属性

我一直在研究: 和 但是,两者都需要
AccessToken
userId
,并且在Lambda函数的上下文中都不可用。我认为唯一的方法是在请求的有效负载中传递一些额外的信息,但这似乎不是真正检索用户属性的最佳方法

编辑

我没有在API上使用自定义授权程序。在使用Amplify设置API时,我选择了受保护的路径,并且所有请求都根据Cognito用户池进行身份验证/授权。在
amplify push
之后,我可以看到部署的API在所有资源的方法请求中的
Auth
下有
AWS_IAM

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代理集成到Lambda函数中。我可以看到Lambda函数正在被调用,因此请求得到了授权。然而,我在Lambda的
事件中所拥有的一切就是我在上面的第一个剪辑中粘贴的内容

鉴于这是一个代理集成,我希望API上下文中的所有内容都应该转发到API后面的Lambda。但是,我看不到如何使用Lambda中提供的任何信息访问用户_属性。有什么建议吗

编辑2

我现在正在研究使用自定义头从客户端传递与用户相关的数据,可能类似于:

'x-user-sub': '58ce94f6-53vd-4s3e-b088-cd6f85s0ff43'
然后在my Lambda函数中使用以下命令获取用户属性:

  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
  }
}
这个解决方案有什么明显的不足之处吗?我是否通过传递客户标题中的
子项
引入了任何安全风险

非常感谢您的帮助。

我想这篇文章可能会对您有所帮助

特别是这一部分:

Cognito用户池的API网关授权程序

API网关最近启动了对Cognito用户池的支持 授权人。如果使用Cognito用户池授权器,则不需要 设置您自己的自定义授权程序以验证令牌。一旦你的API 方法是用Cognito用户池授权器配置的,您可以通过 API方法的授权标头中未过期的ID令牌。如果 它是用户池用户的有效ID令牌,您可以 使用访问API中的所有ID令牌声明 “$context.authorizer.claims”

比如说 “$context.authorizer.claims.email”将返回用户的电子邮件地址 “$context.authorizer.claims.sub”将返回用户的唯一 标识符。如果ID令牌已过期或无效,则Cognito用户 池授权者将向调用方发送未经授权的(401)响应

这里有一些关于如何覆盖apigateway请求/响应参数的示例

您可以看到如何设置集成以及将哪些数据传递到API网关


值得检查映射模板$context.authorizer.claims.sub==userId@pkarfs谢谢你的评论。你是不是建议我把它从API网关转发到Lambda?如果是这样的话,您是否有机会提供一个指针来说明如何做到这一点?也许有什么联系?最后,
userId
是cognito用户的用户名吗?或者我如何使用该变量的值?不用担心,首先,您的event requestContext没有authorizer.claims key对象,我建议这意味着您实际上没有启用/需要authorizer(或者忘记部署rest api)。如果将lambda用作代理,则可以通过lambda将值转发给lambda;如果将lambda用作服务,则可以通过集成映射模板转发。最后,sub是在cognito中分配给用户的唯一值。如果未指定用户名,则yes sub=username。谢谢pkarfs。我使用的是AWS_IAM授权,而不是自定义授权人,不确定这是否与requestContext中没有授权人对象的原因有关。我添加了更多信息来描述流程。此外,我正在API和其背后的Lambda函数之间使用Lambda代理集成,这不意味着API应该自动将与请求相关的所有信息转发给Lambda函数吗?您不应该在标头中传递sub,令牌授权的整个要点是避免需要这样做。此外,如果您使用cognito,为什么要使用AWS_IAM授权?将其更改为您的cognito用户池。这就是您没有收到用户上下文响应的原因。感谢您的回复!对于我是否使用Cognito用户池授权,我不是很有信心。我已经使用amplify/cli部署了API,当我查看AWS API网关控制台时,我在方法请求的“Authorization”下看到了“AWS_IAM”。也许这是一个新的授权流程??同时,我有一个Lambda代理集成,是否所有请求数据都应该包含在
事件中?是否不能使用
事件中我可用的任何属性来检索给定会话的Cognito用户?