

# 使用 Amazon Cognito 用户池作为授权方控制对 REST API 的访问
<a name="apigateway-integrate-with-cognito"></a>

作为使用 [IAM 角色和策略](permissions.md)或 [Lambda 授权方](apigateway-use-lambda-authorizer.md)（以前称为自定义授权方）的替代方案，您可以使用 [Amazon Cognito 用户池](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html)来控制谁可以在 Amazon API Gateway 中访问您的 API。

要将 Amazon Cognito 用户池与您的 API 一起使用，您必须先创建 `COGNITO_USER_POOLS` 类型的授权方，然后配置 API 方法以使用该授权方。部署 API 之后，客户端必须先将用户注册到用户池，获取用户的[身份令牌或访问令牌](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html)，然后使用令牌之一调用 API 方法，这通常设置为请求的 `Authorization` 标头。只有提供了所需的令牌并且提供的令牌有效时，API 调用才会成功，否则，客户端未获得授权来执行调用，因为客户端没有可用于授权的凭证。

使用身份令牌，基于已登录用户的身份声明来授权 API 调用。使用访问令牌，基于指定访问受保护资源的自定义范围授权 API 调用。有关更多信息，请参阅[将令牌与用户池结合使用](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html)和[资源服务器和自定义范围](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-define-resource-servers.html)。

要为 API 创建和配置 Amazon Cognito 用户池，请执行以下任务：
+ 使用 Amazon Cognito 控制台、CLI/开发工具包或 API 创建用户池，或者使用由其他AWS账户拥有的用户池。
+ 使用 API Gateway 控制台、CLI/开发工具包或 API 创建具有选定用户池的 API Gateway Authorizer。
+ 使用 API Gateway 控制台、CLI/开发工具包或 API，在所选 API 方法上启用授权方。

 要在启用了用户池时调用任意 API 方法，您的客户端执行以下任务：
+  使用 Amazon Cognito CLI/SDK 或 API 将用户注册到所选用户池，并获取身份令牌或访问令牌。要了解有关使用 SDK 的更多信息，请参阅 [Code examples for Amazon Cognito using AWS SDKs](https://docs.aws.amazon.com/cognito/latest/developerguide/service_code_examples.html)。
+  使用客户端特定的框架调用已部署的 API Gateway API 并在 `Authorization` 标头中提供合适的令牌。

作为 API 开发人员，您必须向客户端开发人员提供用户池 ID、客户端 ID，并可能需要提供作为用户池的一部分定义的关联客户端密钥。

**注意**  
要允许用户使用 Amazon Cognito 凭证登录，同时还获取用于 IAM 角色权限的临时凭证，请使用 [Amazon Cognito 联合身份](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html)。对于每个 API 资源端点 HTTP 方法，将授权类型、类别 `Method Execution` 设置为 `AWS_IAM`。

在此部分中，我们介绍如何创建用户池、如何将 API Gateway API 与用户池集成，以及如何调用与用户池集成的 API。

**Topics**
+ [为 REST API 创建 Amazon Cognito 授权用户池](apigateway-create-cognito-user-pool.md)
+ [将 REST API 与 Amazon Cognito 用户池集成](apigateway-enable-cognito-user-pool.md)
+ [调用与 Amazon Cognito 用户池集成的 REST API](apigateway-invoke-api-integrated-with-cognito-user-pool.md)
+ [使用 API Gateway 控制台为 REST API 配置跨账户 Amazon Cognito 授权方](apigateway-cross-account-cognito-authorizer.md)
+ [使用 CloudFormation 为 REST API 创建 Amazon Cognito 授权方](apigateway-cognito-authorizer-cfn.md)

# 为 REST API 创建 Amazon Cognito 授权用户池
<a name="apigateway-create-cognito-user-pool"></a>

将 API 与用户池集成之前，您必须在 Amazon Cognito 中创建用户池。您的用户群体配置必须遵守全部 [Amazon Cognito 的资源配额](https://docs.aws.amazon.com/cognito/latest/developerguide/limits.html)。所有用户定义的 Amazon Cognito 变量（如组、用户和角色）应仅使用字母数字字符。有关创建用户群体的说明，请参阅 [Amazon Cognito 开发人员指南](https://docs.aws.amazon.com/cognito/latest/developerguide/tutorial-create-user-pool.html)中的*教程：创建用户池*。

记下用户池 ID、客户端 ID 和任意客户端密钥。客户端必须将这些信息提供给 Amazon Cognito，供用户注册到用户池、登录用户池，并获取要包含在请求中的身份令牌或访问令牌，以便调用配置了用户池的 API 方法。此外，在您将用户池配置为 API Gateway 中的授权方时，您还必须指定用户池名称，如下所述。

如果您使用访问令牌授权 API 方法调用，请确保使用用户池配置应用程序集成，以在指定资源服务器上设置您需要的自定义范围。有关将令牌与 Amazon Cognito 用户池结合使用的更多信息，请参阅[将令牌与用户池结合使用](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html)。有关资源服务器的更多信息，请参阅[为您的用户池定义资源服务器](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-define-resource-servers.html)。

记录配置的资源服务器标识符和自定义范围名称。您需要这些内容来构建 **OAuth Scopes (OAuth 范围)** 的访问范围完整名称，它由 `COGNITO_USER_POOLS` 授权方使用。

![\[Amazon Cognito 用户池资源服务器和范围\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/cognito-user-pool-custom-scopes-new-console.png)


# 将 REST API 与 Amazon Cognito 用户池集成
<a name="apigateway-enable-cognito-user-pool"></a>

创建 Amazon Cognito 用户池后，您必须在 API Gateway 中创建一个使用该用户池的 `COGNITO_USER_POOLS` 授权方。以下过程介绍如何使用 API Gateway 控制台执行此操作。

**注意**  
您可以使用 [https://docs.aws.amazon.com/apigateway/latest/api/API_CreateAuthorizer.html](https://docs.aws.amazon.com/apigateway/latest/api/API_CreateAuthorizer.html) 操作来创建使用多个用户池的 `COGNITO_USER_POOLS` 授权方。一个 `COGNITO_USER_POOLS` 授权方最多可以使用 1000 个用户池。不能提高此限制。

**重要**  
在执行以下任意步骤之后，您都需要部署或重新部署 API 以便传播更改。有关部署 API 的更多信息，请参阅[在 API Gateway 中部署 REST API。](how-to-deploy-api.md)。

**使用 API Gateway 控制台创建 `COGNITO_USER_POOLS` 授权方**

1. 在 API Gateway 中创建新的 API 或选择现有 API。

1. 在主导航窗格中，选择**授权方**。

1. 选择**创建授权方**。

1. 要配置新的授权方来使用用户池，请执行以下操作：

   1.  在**授权方名称**中，输入名称。

   1. 对于**授权方类型**，请选择 **Cognito**。

   1. 对于 **Cognito 用户群体**，请选择您创建 Amazon Cognito 的 AWS 区域并选择可用的用户群体。

      您可以使用阶段变量来定义用户池。对用户池使用以下格式：`arn:aws:cognito-idp:us-east-2:111122223333:userpool/${stageVariables.MyUserPool}`。

   1.  对于**令牌来源**，输入 **Authorization** 作为标头名称，以在用户成功登录时传递 Amazon Cognito 所返回的身份令牌或访问令牌。

   1. （可选）在**令牌验证**字段中输入一个正则表达式，以在使用 Amazon Cognito 对请求进行授权之前，验证身份令牌的 `aud`（受众）字段。请注意，在使用访问令牌时，由于访问令牌不包含 `aud` 字段，此验证将拒绝请求。

   1. 选择**创建授权方**。

1. 创建 `COGNITO_USER_POOLS` 授权方之后，您可以通过提供从用户池预置的身份验证令牌来对其进行测试调用。您不能使用访问令牌来对授权方进行测试调用。

   您可以通过调用 [Amazon Cognito 身份开发工具包](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-integrate-apps.html)来获取此身份令牌以执行用户登录。您也可以使用 [https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) 操作。如果您未配置任何**授权范围**，API Gateway 会将提供的令牌视为身份令牌。

上述过程创建使用新创建的 Amazon Cognito 用户池的 `COGNITO_USER_POOLS` 授权方。根据在 API 方法上启用授权方的方法，您可以使用从集成用户池预置的身份令牌或访问令牌。

**在方法上配置 `COGNITO_USER_POOLS` 授权方**

1. 选择**资源**。选择新方法或选择现有方法。如有必要，请创建资源。

1. 在**方法请求**选项卡上的**方法请求设置**下，选择**编辑**。

1. 对于**授权方**，从下拉菜单中选择您刚刚创建的 **Amazon Cognito 用户群体授权方**。

1.  要使用身份令牌，请执行以下操作：

   1. 将**授权范围**保留为空。

   1. 如果需要，在**集成请求**中，在正文映射模板中添加 `$context.authorizer.claims['property-name']` 或 `$context.authorizer.claims.property-name` 表达式，从而将指定的身份声明属性从用户群体传递到后端。对于简单的属性名称，例如 `sub` 或 `custom-sub`，两种表示法相同。对于复杂的属性名称，例如 `custom:role`，不能使用点表示法。例如，以下映射表达式会将声明的 `sub` 和 `email` 的[标准字段](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)传递到后端：

      ```
      {
      	"context" : {
      		"sub" : "$context.authorizer.claims.sub",
      		"email" : "$context.authorizer.claims.email"
      	}
      }
      ```

      如果您在配置用户池时声明了自定义声明字段，那么您可以用同样的方式来访问自定义字段。以下示例获取的是声明的自定义 `role` 字段：

      ```
      {
      	"context" : {
      		"role" : "$context.authorizer.claims.role"
          }
      }
      ```

      如果自定义声明字段被声明为 `custom:role`，可以使用以下示例来获取声明的属性：

      ```
      {
      	"context" : {
      		"role" : "$context.authorizer.claims['custom:role']"
          }
      }
      ```

1.  要使用访问令牌，请执行以下操作：

   1. 对于**授权范围**，输入某个范围的一个或多个全名，该范围在创建 Amazon Cognito 用户池时已配置。例如，根据 [为 REST API 创建 Amazon Cognito 授权用户池](apigateway-create-cognito-user-pool.md) 中给出的示例，其中一个范围是 `https://my-petstore-api.example.com/cats.read`。

      在运行时，如果在此步骤的方法上指定的任何范围与在传入令牌中声明的范围匹配，则方法调用成功。否则，调用失败并出现 `401 Unauthorized` 响应。

   1.  选择**保存**。

1. 对您选择的其他方法重复这些步骤。

使用 `COGNITO_USER_POOLS` 授权方，如果未指定 **OAuth 范围**选项，则 API Gateway 将提供的令牌视为身份令牌，并根据来自用户池的身份之一验证所声明的身份。否则，API Gateway 将提供的令牌视为访问令牌，并根据在方法上声明的授权范围，验证在令牌中所声明的访问范围。

除了使用 API Gateway 控制台之外，您还可以指定 OpenAPI 定义文件并将 API 定义导入到 API Gateway，从而在方法上启用 Amazon Cognito 用户池。

**用 OpenAPI 定义文件导入 COGNITO\$1USER\$1POOLS 授权方**

1. 为您的 API 创建（或导出）一个 OpenAPI 定义文件。

1. 作为 OpenAPI 3.0 中的 `COGNITO_USER_POOLS` 部分或 Open API 2.0 中的 `MyUserPool` 部分，指定 `securitySchemes` 授权方 (`securityDefinitions`) JSON 定义，如下所示：

------
#### [ OpenAPI 3.0 ]

   ```
     "securitySchemes": {
       "MyUserPool": {
         "type": "apiKey",
         "name": "Authorization",
         "in": "header",
         "x-amazon-apigateway-authtype": "cognito_user_pools",
         "x-amazon-apigateway-authorizer": {
           "type": "cognito_user_pools",
           "providerARNs": [
             "arn:aws:cognito-idp:{region}:{account_id}:userpool/{user_pool_id}"
           ]
         }
       }
   ```

------
#### [ OpenAPI 2.0 ]

   ```
     "securityDefinitions": {
       "MyUserPool": {
         "type": "apiKey",
         "name": "Authorization",
         "in": "header",
         "x-amazon-apigateway-authtype": "cognito_user_pools",
         "x-amazon-apigateway-authorizer": {
           "type": "cognito_user_pools",
           "providerARNs": [
             "arn:aws:cognito-idp:{region}:{account_id}:userpool/{user_pool_id}"
           ]
         }
       }
   ```

------

1. 要将身份令牌用于方法授权，请将 `{ "MyUserPool": [] }` 添加到方法的 `security` 定义，如根资源上的以下 GET 方法所示。

   ```
     "paths": {
       "/": {
         "get": {
           "consumes": [
             "application/json"
           ],
           "produces": [
             "text/html"
           ],
           "responses": {
             "200": {
               "description": "200 response",
               "headers": {
                 "Content-Type": {
                   "type": "string"
                 }
               }
             }
           },
           "security": [
             {
               "MyUserPool": []
             }
           ],        
           "x-amazon-apigateway-integration": {
             "type": "mock",
             "responses": {
               "default": {
                 "statusCode": "200",
                 "responseParameters": {
                   "method.response.header.Content-Type": "'text/html'"
                 },
               }
             },
             "requestTemplates": {
               "application/json": "{\"statusCode\": 200}"
             },
             "passthroughBehavior": "when_no_match"
           }
         },
         ...
      }
   ```

1.  要为方法授权使用访问令牌，请将以上安全定义更改为 `{ "MyUserPool": [resource-server/scope, ...] }`：

   ```
     "paths": {
       "/": {
         "get": {
           "consumes": [
             "application/json"
           ],
           "produces": [
             "text/html"
           ],
           "responses": {
             "200": {
               "description": "200 response",
               "headers": {
                 "Content-Type": {
                   "type": "string"
                 }
               }
             }
           },
           "security": [
             {
               "MyUserPool": ["https://my-petstore-api.example.com/cats.read", "http://my.resource.com/file.read"]
             }
           ],        
           "x-amazon-apigateway-integration": {
             "type": "mock",
             "responses": {
               "default": {
                 "statusCode": "200",
                 "responseParameters": {
                   "method.response.header.Content-Type": "'text/html'"
                 },
               }
             },
             "requestTemplates": {
               "application/json": "{\"statusCode\": 200}"
             },
             "passthroughBehavior": "when_no_match"
           }
         },
         ...
      }
   ```

1. 如果需要，您可以使用合适的 OpenAPI 定义或扩展来设置其他 API 配置设置。有关更多信息，请参阅 [适用于 API Gateway 的 OpenAPI 扩展](api-gateway-swagger-extensions.md)。

# 调用与 Amazon Cognito 用户池集成的 REST API
<a name="apigateway-invoke-api-integrated-with-cognito-user-pool"></a>

要调用一个配置了用户池授权方的方法，客户端必须执行以下操作：
+ 让用户注册到用户池中。
+ 让用户登录用户池。
+ 从用户池获取已登录用户的[身份或访问令牌](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html)。
+ 将令牌添加到 `Authorization` 标头（或您创建授权方时指定的其他标头）中。

您可以使用 [AWS Amplify]() 来执行这些任务。有关更多信息，请参阅[将 Amazon Cognito 与 Web 和移动应用程序集成](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-integrate-apps.html)。
+ 对于 Android，请参阅 [Amplify for Android 入门](https://docs.amplify.aws/android/build-a-backend/auth/)。
+ 要使用 iOS，请参阅 [Amplify for iOS 入门](https://docs.amplify.aws/swift/build-a-backend/auth/)。
+ 要使用 JavaScript，请参阅 [Amplify for Javascript 入门](https://docs.amplify.aws/javascript/build-a-backend/auth/)。

# 使用 API Gateway 控制台为 REST API 配置跨账户 Amazon Cognito 授权方
<a name="apigateway-cross-account-cognito-authorizer"></a>

您现在还可以使用来自其他 AWS 账户的 Amazon Cognito 用户池作为 API 授权方。Amazon Cognito 用户池可使用持有者令牌身份验证策略（如 OAuth 或 SAML）。这样就可以轻松地跨多个 API Gateway API 集中管理和共享中央 Amazon Cognito 用户池授权方。

在本节中，我们将介绍如何使用 Amazon API Gateway 控制台配置跨账户 Amazon Cognito 用户池。

这些说明假定您已在一个 AWS 账户中拥有 API Gateway API，在另一个账户中有 Amazon Cognito 用户池。

## 为 REST API 创建跨账户 Amazon Cognito 授权方
<a name="apigateway-configure-cross-account-cognito-authorizer"></a>

在您拥有 API 的账户中登录 Amazon API Gateway 控制台，然后执行以下操作：

1. 在 API Gateway 中创建新的 API 或选择现有 API。

1. 在主导航窗格中，选择**授权方**。

1. 选择**创建授权方**。

1. 要配置新的授权方来使用用户池，请执行以下操作：

   1.  在**授权方名称**中，输入名称。

   1. 对于**授权方类型**，请选择 **Cognito**。

   1. 对于 **Cognito 用户群体**，输入您第二个账户中的用户群体的完整 ARN。
**注意**  
在 Amazon Cognito 控制台中，您可以在**常规设置**窗格的**池 ARN** 字段找到您的用户池的 ARN。

   1.  对于**令牌来源**，输入 **Authorization** 作为标头名称，以在用户成功登录时传递 Amazon Cognito 所返回的身份令牌或访问令牌。

   1. （可选）在**令牌验证**字段中输入一个正则表达式，以在使用 Amazon Cognito 对请求进行授权之前，验证身份令牌的 `aud`（受众）字段。请注意，在使用访问令牌时，由于访问令牌不包含 `aud` 字段，此验证将拒绝请求。

   1. 选择**创建授权方**。

# 使用 CloudFormation 为 REST API 创建 Amazon Cognito 授权方
<a name="apigateway-cognito-authorizer-cfn"></a>

可以使用 CloudFormation 创建 Amazon Cognito 用户群体和 Amazon Cognito 授权方。示例 CloudFormation 模板执行以下操作：
+ 创建 Amazon Cognito 用户群体。客户端必须先将用户登录到用户群体并获取[身份或访问令牌](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html)。如果您使用访问令牌授权 API 方法调用，请确保使用用户池配置应用程序集成，以在指定资源服务器上设置您需要的自定义范围。
+ 使用 `GET` 方法创建 API Gateway API。
+ 创建使用 `Authorization` 标头作为令牌来源的 Amazon Cognito 授权方。

```
AWSTemplateFormatVersion: 2010-09-09
Resources:
  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      AccountRecoverySetting:
        RecoveryMechanisms:
          - Name: verified_phone_number
            Priority: 1
          - Name: verified_email
            Priority: 2
      AdminCreateUserConfig:
        AllowAdminCreateUserOnly: true
      EmailVerificationMessage: The verification code to your new account is {####}
      EmailVerificationSubject: Verify your new account
      SmsVerificationMessage: The verification code to your new account is {####}
      VerificationMessageTemplate:
        DefaultEmailOption: CONFIRM_WITH_CODE
        EmailMessage: The verification code to your new account is {####}
        EmailSubject: Verify your new account
        SmsMessage: The verification code to your new account is {####}
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
  CogAuthorizer:
    Type: AWS::ApiGateway::Authorizer
    Properties:
      Name: CognitoAuthorizer
      RestApiId:
        Ref: Api
      Type: COGNITO_USER_POOLS
      IdentitySource: method.request.header.Authorization
      ProviderARNs:
        - Fn::GetAtt:
            - UserPool
            - Arn
  Api:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: MyCogAuthApi
  ApiDeployment:
    Type: AWS::ApiGateway::Deployment
    Properties:
      RestApiId:
        Ref: Api
    DependsOn:
      - CogAuthorizer
      - ApiGET
  ApiDeploymentStageprod:
    Type: AWS::ApiGateway::Stage
    Properties:
      RestApiId:
        Ref: Api
      DeploymentId:
        Ref: ApiDeployment
      StageName: prod
  ApiGET:
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: GET
      ResourceId:
        Fn::GetAtt:
          - Api
          - RootResourceId
      RestApiId:
        Ref: Api
      AuthorizationType: COGNITO_USER_POOLS
      AuthorizerId:
        Ref: CogAuthorizer
      Integration:
        IntegrationHttpMethod: GET
        Type: HTTP_PROXY
        Uri: http://petstore-demo-endpoint.execute-api.com/petstore/pets
Outputs:
  ApiEndpoint:
    Value:
      Fn::Join:
        - ""
        - - https://
          - Ref: Api
          - .execute-api.
          - Ref: AWS::Region
          - "."
          - Ref: AWS::URLSuffix
          - /
          - Ref: ApiDeploymentStageprod
          - /
```