【问题标题】:How do I call an API Gateway with Cognito credentials in Python如何在 Python 中使用 Cognito 凭据调用 API 网关
【发布时间】:2016-09-17 02:31:06
【问题描述】:

我已经成功设置了一个使用 Cognito 保护的 API 网关。未经身份验证的用户角色有一个访问策略,应该授予它访问网关的权限。我还设法使用 boto3 从池中检索身份 ID 并获取关联的开放 ID 令牌,以及关联的密钥和访问密钥。

我现在如何使用这些凭据调用网关?有没有办法使用 boto3 来处理对 API 上特定方法的请求的签名?

【问题讨论】:

    标签: python python-3.x amazon-web-services amazon-cognito boto3


    【解决方案1】:

    我的代码主要基于提问者自己的答案,但我试图更清楚地说明所有值的来源。

    import boto3
    import requests
    from requests_aws4auth import AWS4Auth
    # Use 'pip install boto3 requests requests-aws4auth' to get these
    
    region_name = 'ap-southeast-2' # or 'us-west-1' or whatever
    
    # 12 decimal digits from your AWS login page
    account_id = '123456789012'
    
    # I've only found this in the sample code for other languages, e.g. JavaScript
    # Services→Cognito→Manage Federated Identities→(your-id-pool)→Sample code
    identity_pool_id = 'ap-southeast-2:fedcba98-7654-3210-1234-56789abcdef0'
    
    # Create a new identity
    boto3.setup_default_session(region_name = region_name)
    identity_client = boto3.client('cognito-identity', region_name=region_name)
    identity_response = identity_client.get_id(AccountId=account_id,
        IdentityPoolId=identity_pool_id)
    
    # We normally wouldn't log this, but to illustrate:
    identity_id = identity_response['IdentityId']
    print ('identity_id:', identity_id) # good idea not to log this
    
    # Get the identity's credentials
    credentials_response = identity_client.get_credentials_for_identity(IdentityId=identity_id)
    credentials = credentials_response['Credentials']
    access_key_id = credentials['AccessKeyId']
    secret_key = credentials['SecretKey']
    service = 'execute-api'
    session_token = credentials['SessionToken']
    expiration = credentials['Expiration']
    # Again, we normally wouldn't log this:
    print ('access_key_id', access_key_id)
    print ('secret_key', secret_key)
    print ('session_token', session_token)
    print ('expiration', expiration)
    # The access_key_id will look something like 'AKIABC123DE456FG7890', similar to
    # Services→IAM→Users→(AWS_USER_NAME)→Security credentials→Access key ID
    
    # Get the authorisation object
    auth = AWS4Auth(access_key_id, secret_key, region_name, service,
        session_token=session_token)
    current_app['auth'] = auth
    # Just an illustration again:
    print ('auth: %(service)s(%(date)s) %(region)s:%(access_id)s' % auth.__dict__)
    
    # We'll use that object to send a request to our app. This app doesn't
    # exist in real life, though, so you'll need to edit the following quite
    # heavily:
    
    # Services→Cognito→Manage your User Pools→(your-user-pool)→Apps→App name
    app_name = 'my-app-name'
    
    api_path = 'dev/helloworld'
    method = 'GET'
    headers = {}
    body = ''
    url = 'https://%s.%s.%s.amazonaws.com/%s' % (app_name, service, region_name,
        api_path)
    response = requests.request(method, url, auth=auth, data=body, headers=headers)
    

    【讨论】:

    • 感谢您记录 ID 值。这也让我挂了。不幸的是,此代码不适用于用户池,仅适用于身份池。
    【解决方案2】:

    以下代码(和 requests-aws4auth 库)完成了这项工作:

    import boto3
    import datetime
    import json
    from requests_aws4auth import AWS4Auth
    import requests
    
    boto3.setup_default_session(region_name='us-east-1')
    identity = boto3.client('cognito-identity', region_name='us-east-1')
    
    account_id='XXXXXXXXXXXXXXX'
    identity_pool_id='us-east-1:YYY-YYYY-YYY-YY'
    api_prefix='ZZZZZZZZZ'
    
    response = identity.get_id(AccountId=account_id, IdentityPoolId=identity_pool_id)
    identity_id = response['IdentityId']
    print ("Identity ID: %s"%identity_id)
    
    resp = identity.get_credentials_for_identity(IdentityId=identity_id)
    secretKey = resp['Credentials']['SecretKey']
    accessKey = resp['Credentials']['AccessKeyId']
    sessionToken = resp['Credentials']['SessionToken']
    expiration = resp['Credentials']['Expiration']
    
    print ("\nSecret Key: %s"%(secretKey))
    print ("\nAccess Key %s"%(accessKey))
    print ("\nSession Token: %s"%(sessionToken))
    print ("\nExpiration: %s"%(expiration))
    
    method = 'GET'
    headers = {}
    body = ''
    service = 'execute-api'
    url = 'https://%s.execute-api.us-east-1.amazonaws.com/dev/helloworld' % api_prefix
    region = 'us-east-1'
    
    auth = AWS4Auth(accessKey, secretKey, region, service, session_token=sessionToken)
    response = requests.request(method, url, auth=auth, data=body, headers=headers)
    print(response.text)
    

    【讨论】:

    • api_prefix 是从哪里来的?谢谢!
    • @Efren 我相信当您访问 API 网关应用程序的管理部分时,您可以在 AWS 控制台中找到它,即 .execute-api.us-east-1。 amazonaws.com 。在管理区域中,单击左侧的资源部分,然后单击网关中的一个端点,即 /pets,包含前缀的完整 URL 将显示在右侧
    • 您能否描述一下从哪里获取其他值?我敢肯定,对于使用 AIM 时间比我长的人来说,这很明显,但是这段代码对我不起作用,所以我可能从错误的地方得到 account_idapi_prefix。我什至不确定我的identity_pool_id 是否正确;当我转到用户池→池详细信息→池 ID 时,我的中有一个下划线,而不是像您的示例中那样的冒号(就像在 boto3.readthedocs.io/en/latest/reference/services/… 的文档中一样)
    • 我最终让它工作了。我的主要困惑是在用户池和身份池之间。我已经发布了自己的答案,希望可以更清楚地了解在哪里获取所需的值。
    【解决方案3】:

    下一个代码运行良好。

    希望能提供帮助:

    from pprint import pprint
    import requests
    from pycognito import Cognito
    
    
    USER_POOL_ID = 'eu-central-1_XXXXXXXXXXX'
    CLIENT_ID = 'XXXXXXXXXXXX'
    CLIENT_SECRET = 'XXXXXXXXXXX'
    
    u = Cognito(USER_POOL_ID,CLIENT_ID, client_secret=CLIENT_SECRET, username='cognito user name')
    u.authenticate('cognito user password')
    
    id_token = u.id_token
    
    headers = {'Authorization':  'Bearer ' + id_token}
    api_url = 'https://XXXXXXXXXXX.execute-api.eu-central-1.amazonaws.com/stage/XXXXXXXXXXX'
    
    r = requests.get(api_url, headers=headers)
    pprint(dict(r.headers))
    print(r.status_code)
    print(r.text)
    

    【讨论】:

      【解决方案4】:

      这是我们公共文档中的一个示例:http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html

      Cognito 信用与其他任何临时信用没有什么不同,签名过程也相同。如果你想回到 Python 上面的例子应该很好,或者我猜有第三方库可以为你做签名。

      【讨论】:

      • 是否有一个功能可以添加为 API 网关生成 Python SDK 的能力,就像目前 OSX、Android 和 Javascript 的情况一样?我已经看过您提供的示例文档,但是当 Javascript SDK 满足即时要求时,它最终过于冗长而无法被打扰。不过,我会寻找一个现有的 Python sigv4 库。我是否遵循本节并使用身份验证标头然后调用 API 网关上的方法docs.aws.amazon.com/general/latest/gr/…
      • 是的,它在我们的积压工作中,最终我们希望支持 AWS 为服务发布的相同 SDK,但没有 ETA。就滚动您自己而言,是的,您可以将签名库从现有的 Python SDK 中提取出来,只需将服务名称更改为“execute-api”
      • @LaserJesus:我相信你的回答,几个月后,使用 Jack 所说的 API 正在开发中?如果是这样,我会投票作为接受的答案。
      【解决方案5】:

      identity_pool_id如何获取

      如果您还没有可以为您提供 "identity_pool_id" 的联合池, 下面的执行代码会给你 identity_pool_id

      import boto3
      boto3.setup_default_session(
          aws_access_key_id='AKIAJ7TBC72BPWNEWIDQ', 
          aws_secret_access_key='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', 
          region_name='ap-southeast-2')
      
      client = boto3.client('cognito-identity')
      response = client.list_identity_pools(MaxResults=3,)
      
      print("IdentityPoolId-- ", response)
      

      【讨论】:

        猜你喜欢
        • 2019-06-19
        • 2016-09-22
        • 2021-06-11
        • 1970-01-01
        • 1970-01-01
        • 2016-09-06
        • 1970-01-01
        • 2019-01-15
        • 2017-02-04
        相关资源
        最近更新 更多