

# 控制和管理对 API Gateway 中的 HTTP API 的访问
<a name="http-api-access-control"></a>

API Gateway 支持多种用于控制和管理对 HTTP API 的访问的机制：
+ **Lambda 授权方** 使用 Lambda 函数来控制对 API 的访问。有关更多信息，请参阅 [使用 Amazon Lambda 授权方控制对 HTTP API 的访问](http-api-lambda-authorizer.md)。
+ **JWT 授权方** 使用 JSON Web 令牌来控制对 API 的访问。有关更多信息，请参阅 [在 API Gateway 中使用 JWT 授权方控制对 HTTP API 的访问](http-api-jwt-authorizer.md)。
+ **标准Amazon IAM 角色和策略**提供灵活且稳健的访问控制。您可以使用 IAM 角色和策略来控制哪些人可以创建和管理您的 API，以及谁可以调用它们。有关更多信息，请参阅 [在 API Gateway 中使用 IAM 授权来控制对 HTTP API 的访问](http-api-access-control-iam.md)。

为了改善您的安全状况，我们建议您为 HTTP API 上的所有路由配置授权方。为遵守各种合规性框架，您可能需要执行此操作。有关更多信息，请参阅《Amazon Security Hub User Guide》**中的 [Amazon API Gateway Controls](https://docs.amazonaws.cn/securityhub/latest/userguide/apigateway-controls.html)。

# 使用 Amazon Lambda 授权方控制对 HTTP API 的访问
<a name="http-api-lambda-authorizer"></a>

您可以使用 Lambda 授权方以通过 Lambda 函数控制对 HTTP API 的访问。然后，当客户端调用您的 API 时，API Gateway 会调用您的 Lambda 函数。API Gateway 使用来自 Lambda 函数的响应来确定客户端是否可以访问您的 API。

## 负载格式版本
<a name="http-api-lambda-authorizer.payload-format"></a>

授权方负载格式版本指定 API Gateway 发送到 Lambda 授权方的数据格式，以及 API Gateway 如何解释来自 Lambda 的响应。如果未指定负载格式版本，则默认情况下 Amazon Web Services 管理控制台 使用最新版本。如果您通过使用 Amazon CLI、Amazon CloudFormation 或开发工具包创建 Lambda 授权方，则必须指定 `authorizerPayloadFormatVersion`。支持的值是 `1.0` 和 `2.0`。

 如果您需要与 REST API 兼容，请使用版本 `1.0`。

以下示例显示了每个负载格式版本的结构。

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

```
{
  "version": "2.0",
  "type": "REQUEST",
  "routeArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request",
  "identitySource": ["user1", "123"],
  "routeKey": "$default",
  "rawPath": "/my/path",
  "rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value",
  "cookies": ["cookie1", "cookie2"],
  "headers": {
    "header1": "value1",
    "header2": "value2"
  },
  "queryStringParameters": {
    "parameter1": "value1,value2",
    "parameter2": "value"
  },
  "requestContext": {
    "accountId": "123456789012",
    "apiId": "api-id",
    "authentication": {
      "clientCert": {
        "clientCertPem": "CERT_CONTENT",
        "subjectDN": "www.example.com",
        "issuerDN": "Example issuer",
        "serialNumber": "1",
        "validity": {
          "notBefore": "May 28 12:30:02 2019 GMT",
          "notAfter": "Aug  5 09:36:04 2021 GMT"
        }
      }
    },
    "domainName": "id.execute-api.us-east-1.amazonaws.com",
    "domainPrefix": "id",
    "http": {
      "method": "POST",
      "path": "/my/path",
      "protocol": "HTTP/1.1",
      "sourceIp": "IP",
      "userAgent": "agent"
    },
    "requestId": "id",
    "routeKey": "$default",
    "stage": "$default",
    "time": "12/Mar/2020:19:03:58 +0000",
    "timeEpoch": 1583348638390
  },
  "pathParameters": { "parameter1": "value1" },
  "stageVariables": { "stageVariable1": "value1", "stageVariable2": "value2" }
}
```

------
#### [ 1.0 ]

```
{
  "version": "1.0",
  "type": "REQUEST",
  "methodArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request",
  "identitySource": "user1,123",
  "authorizationToken": "user1,123",
  "resource": "/request",
  "path": "/request",
  "httpMethod": "GET",
  "headers": {
    "X-AMZ-Date": "20170718T062915Z",
    "Accept": "*/*",
    "HeaderAuth1": "headerValue1",
    "CloudFront-Viewer-Country": "US",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Is-Mobile-Viewer": "false",
    "User-Agent": "..."
  },
  "queryStringParameters": {
    "QueryString1": "queryValue1"
  },
  "pathParameters": {},
  "stageVariables": {
    "StageVar1": "stageValue1"
  },
  "requestContext": {
    "path": "/request",
    "accountId": "123456789012",
    "resourceId": "05c7jb",
    "stage": "test",
    "requestId": "...",
    "identity": {
      "apiKey": "...",
      "sourceIp": "...",
      "clientCert": {
        "clientCertPem": "CERT_CONTENT",
        "subjectDN": "www.example.com",
        "issuerDN": "Example issuer",
        "serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1",
        "validity": {
          "notBefore": "May 28 12:30:02 2019 GMT",
          "notAfter": "Aug  5 09:36:04 2021 GMT"
        }
      }
    },
    "resourcePath": "/request",
    "httpMethod": "GET",
    "apiId": "abcdef123"
  }
}
```

------

## Lambda 授权方响应格式
<a name="http-api-lambda-authorizer.payload-format-response"></a>

负载格式版本还确定您必须从 Lambda 函数返回的响应的结构。

### 格式 1.0 的 Lambda 函数响应
<a name="http-api-lambda-authorizer.v1"></a>

如果您选择 `1.0` 格式版本， Lambda 授权方必须返回允许或拒绝访问您的 API 路由的 IAM 策略。您可以在策略中使用标准 IAM 语法。有关 IAM 策略的示例，请参阅 [针对调用 API 的访问控制](api-gateway-control-access-using-iam-policies-to-invoke-api.md)。您可以使用 `$context.authorizer.property` 将上下文属性传递到 Lambda 集成或访问日志。`context` 对象是可选的，`claims` 是保留的占位符，不能用作上下文对象。要了解更多信息，请参阅“[自定义 HTTP API 访问日志](http-api-logging-variables.md)”。

**Example**    
****  

```
{
  "principalId": "abcdef", 
  "policyDocument": {
    "Version":"2012-10-17",		 	 	 
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow|Deny",
        "Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]"
      }
    ]
  },
  "context": {
    "exampleKey": "exampleValue"
  }
}
```

### 格式 2.0 的 Lambda 函数响应
<a name="http-api-lambda-authorizer.v2"></a>

如果选择 `2.0` 格式版本，则可以从 Lambda 函数中返回使用标准 IAM 策略语法的布尔值或 IAM 策略。要返回布尔值，请为授权方启用简单响应。以下示例演示您必须对 Lambda 函数进行编码才能返回的格式。`context` 对象是可选的。您可以使用 `$context.authorizer.property` 将上下文属性传递到 Lambda 集成或访问日志。要了解更多信息，请参阅“[自定义 HTTP API 访问日志](http-api-logging-variables.md)”。

------
#### [ Simple response ]

```
{
  "isAuthorized": true/false,
  "context": {
    "exampleKey": "exampleValue"
  }
}
```

------
#### [ IAM policy ]

****  

```
{
  "principalId": "abcdef", 
  "policyDocument": {
    "Version":"2012-10-17",		 	 	 
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow|Deny",
        "Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]"
      }
    ]
  },
  "context": {
    "exampleKey": "exampleValue"
  }
}
```

------

## Lambda 授权方函数示例
<a name="http-api-lambda-authorizer.example-code"></a>

以下示例 Node.js Lambda 函数演示您需要从 `2.0` 负载格式版本的 Lambda 函数返回的所需响应格式。

------
#### [ Simple response - Node.js ]

```
export const handler = async(event) => {
    let response = {
        "isAuthorized": false,
        "context": {
            "stringKey": "value",
            "numberKey": 1,
            "booleanKey": true,
            "arrayKey": ["value1", "value2"],
            "mapKey": {"value1": "value2"}
        }
    };
    
    if (event.headers.authorization === "secretToken") {
        console.log("allowed");
        response = {
            "isAuthorized": true,
            "context": {
                "stringKey": "value",
                "numberKey": 1,
                "booleanKey": true,
                "arrayKey": ["value1", "value2"],
                "mapKey": {"value1": "value2"}
            }
        };
    }

    return response;

};
```

------
#### [ Simple response - Python ]

```
import json


def lambda_handler(event, context):
    response = {
        "isAuthorized": False,
        "context": {
            "stringKey": "value",
            "numberKey": 1,
            "booleanKey": True,
            "arrayKey": ["value1", "value2"],
            "mapKey": {"value1": "value2"}
        }
    }

    try:
        if (event["headers"]["authorization"] == "secretToken"):
            response = {
                "isAuthorized": True,
                "context": {
                    "stringKey": "value",
                    "numberKey": 1,
                    "booleanKey": True,
                    "arrayKey": ["value1", "value2"],
                    "mapKey": {"value1": "value2"}
                }
            }
            print('allowed')
            return response
        else:
            print('denied')
            return response
    except BaseException:
        print('denied')
        return response
```

------
#### [ IAM policy - Node.js ]

```
export const handler = async(event) => {
  if (event.headers.authorization == "secretToken") {
    console.log("allowed");
    return {
      "principalId": "abcdef", // The principal user identification associated with the token sent by the client.
      "policyDocument": {
        "Version": "2012-10-17",		 	 	 
        "Statement": [{
          "Action": "execute-api:Invoke",
          "Effect": "Allow",
          "Resource": event.routeArn
        }]
      },
      "context": {
        "stringKey": "value",
        "numberKey": 1,
        "booleanKey": true,
        "arrayKey": ["value1", "value2"],
        "mapKey": { "value1": "value2" }
      }
    };
  }
  else {
    console.log("denied");
    return {
      "principalId": "abcdef", // The principal user identification associated with the token sent by the client.
      "policyDocument": {
        "Version": "2012-10-17",		 	 	 
        "Statement": [{
          "Action": "execute-api:Invoke",
          "Effect": "Deny",
          "Resource": event.routeArn
        }]
      },
      "context": {
        "stringKey": "value",
        "numberKey": 1,
        "booleanKey": true,
        "arrayKey": ["value1", "value2"],
        "mapKey": { "value1": "value2" }
      }
    };
  }
};
```

------
#### [ IAM policy - Python ]

```
import json


def lambda_handler(event, context):
    response = {
        # The principal user identification associated with the token sent by
        # the client.
        "principalId": "abcdef",
        "policyDocument": {
            "Version": "2012-10-17",		 	 	 
            "Statement": [{
                "Action": "execute-api:Invoke",
                "Effect": "Deny",
                "Resource": event["routeArn"]
            }]
        },
        "context": {
            "stringKey": "value",
            "numberKey": 1,
            "booleanKey": True,
            "arrayKey": ["value1", "value2"],
            "mapKey": {"value1": "value2"}
        }
    }

    try:
        if (event["headers"]["authorization"] == "secretToken"):
            response = {
                # The principal user identification associated with the token
                # sent by the client.
                "principalId": "abcdef",
                "policyDocument": {
                    "Version": "2012-10-17",		 	 	 
                    "Statement": [{
                        "Action": "execute-api:Invoke",
                        "Effect": "Allow",
                        "Resource": event["routeArn"]
                    }]
                },
                "context": {
                    "stringKey": "value",
                    "numberKey": 1,
                    "booleanKey": True,
                    "arrayKey": ["value1", "value2"],
                    "mapKey": {"value1": "value2"}
                }
            }
            print('allowed')
            return response
        else:
            print('denied')
            return response
    except BaseException:
        print('denied')
        return response
```

------

## 身份来源
<a name="http-api-lambda-authorizer.identity-sources"></a>

您可以选择指定 Lambda 授权方的身份来源。身份来源指定对请求进行授权所需的数据的位置。例如，您可以将标头或查询字符串值指定为身份来源。如果您指定身份来源，则客户端必须将其包含在请求中。如果客户端的请求不包括身份源，则 API Gateway 不会调用您的 Lambda 授权方，客户端会收到 `401` 错误。

下表描述了 Lambda 授权方支持的身份源。


| **Type** | **示例** | **备注**： | 
| --- | --- | --- | 
| 标头值 | \$1request.header.name | 标头名称不区分大小写。 | 
| 查询字符串值 | \$1request.querystring.name | 查询字符串名称区分大小写。 | 
| 上下文变量 | \$1context.variableName | 受支持的[上下文变量](http-api-logging-variables.md)的值。 | 
| 阶段变量 | \$1stageVariables.variableName | [阶段变量](http-api-stages.stage-variables.md)的值。 | 

也可以直接从 Lambda 函数返回 ` {"errorMessage" : "Unauthorized"}`，来向您的客户端返回 `401` 错误。如果您直接从 Lambda 函数向客户端返回 `401` 错误，则在创建 Lambda 授权方时不要指定任何身份来源。

## 缓存授权方响应
<a name="http-api-lambda-authorizer.caching"></a>

您可以通过指定 [authorizerResultTtlInSeconds](https://docs.amazonaws.cn/apigatewayv2/latest/api-reference/apis-apiid-authorizers.html#apis-apiid-authorizers-prop-createauthorizerinput-authorizerresultttlinseconds) 为 Lambda 授权方启用缓存。为授权方启用缓存时，API Gateway 使用授权方的身份来源作为缓存密钥。如果客户端在配置的 TTL 内在身份来源中指定了相同的参数，则 API Gateway 使用缓存的授权方结果，而不调用 Lambda 函数。

要启用缓存，授权方必须至少有一个身份来源。

如果为授权方启用简单响应，则授权方的响应将完全允许或拒绝与缓存的身份来源值匹配的所有 API 请求。要获得更精细的权限，请禁用简单响应并返回 IAM 策略。根据授权方，IAM 策略可能需要控制对多个身份来源的访问权限。

默认情况下，API Gateway 对使用授权方的 API 的所有路由使用缓存的授权方响应。要缓存每条路由的响应，请将 `$context.routeKey` 添加到授权方的身份来源中。

## 创建 Lambda 授权方
<a name="http-api-lambda-authorizer.example-create"></a>

创建 Lambda 授权方时，需要指定供 API Gateway 使用的 Lambda 函数。您必须使用函数的资源策略或 IAM 角色向 API Gateway 授予调用 Lambda 函数的权限。以下 [create-authorizer](https://docs.amazonaws.cn/cli/latest/reference/apigatewayv2/create-authorizer.html) 命令创建 Lambda 授权方：

```
aws apigatewayv2 create-authorizer \
    --api-id abcdef123 \
    --authorizer-type REQUEST \
    --identity-source '$request.header.Authorization' \
    --name lambda-authorizer \ 
    --authorizer-uri 'arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:my-function/invocations' \
    --authorizer-payload-format-version '2.0' \
    --enable-simple-responses
```

以下 [add-permission](https://docs.amazonaws.cn/cli/latest/reference/lambda/add-permission.html) 命令更新 Lambda 函数的资源策略，来授予 API Gateway 调用函数的权限。如果 API Gateway 没有调用函数的权限，客户端会收到 `500 Internal Server Error`。

```
aws lambda add-permission \
    --function-name my-authorizer-function \
    --statement-id apigateway-invoke-permissions-abc123 \ 
    --action lambda:InvokeFunction \
    --principal apigateway.amazonaws.com \
    --source-arn "arn:aws:execute-api:us-west-2:123456789012:api-id/authorizers/authorizer-id"
```

创建授权方并授予 API Gateway 调用授权方的权限后，请更新您的路由以使用此授权方。以下 [update-route](https://docs.amazonaws.cn/cli/latest/reference/apigatewayv2/update-route.html) 命令将 Lambda 授权方添加到路由中。如果 Lambda 授权方使用策略缓存，请务必更新策略以控制其它路由的访问权限。

```
aws apigatewayv2 update-route \
    --api-id abcdef123 \
    --route-id abc123 \
    --authorization-type CUSTOM \
    --authorizer-id def123
```

## Lambda 授权方故障排除
<a name="http-api-lambda-authorizer.troubleshooting"></a>

如果 API Gateway 无法调用 Lambda 授权方，或者您的 Lambda 授权方返回无效格式的响应，则客户端将收到 `500 Internal Server Error`。

要排除错误，请为 API 阶段[启用访问日志记录](http-api-logging.md)。以 `$context.authorizer.error` 日志格式包含日志记录变量。

如果日志表明 API Gateway 无权调用您的函数，请更新函数的资源策略或提供 IAM 角色，以授予 API Gateway 调用授权方的权限。

如果日志表明您的 Lambda 函数返回无效响应，请验证您的 Lambda 函数以[所需格式](#http-api-lambda-authorizer.payload-format-response)返回响应。

# 在 API Gateway 中使用 JWT 授权方控制对 HTTP API 的访问
<a name="http-api-jwt-authorizer"></a>

您可以使用 JSON Web 令牌 (JWT) 作为 [OpenID Connect (OIDC)](https://openid.net/specs/openid-connect-core-1_0.html) 和 [OAuth 2.0](https://oauth.net/2/) 框架的一部分来限制客户端对您的 API 的访问。

如果您为 API 的路由配置 JWT 授权方，API Gateway 将验证客户端通过 API 请求提交的 JWT。API Gateway 根据令牌中的令牌验证和（可选）作用域来允许或拒绝请求。如果为路由配置作用域，则令牌必须至少包含路由的作用域之一。

您可以为 API 的每个路由配置不同的授权方，也可以为多个路由使用同一个授权方。

**注意**  
没有标准的机制可以将 JWT 访问令牌与其他类型的 JWT（如 OpenID Connect ID 令牌）区分开来。除非您需要 ID 令牌进行 API 授权，否则我们建议您将路由配置为需要授权范围。您还可以将 JWT 授权方配置为需要相应的发布者或受众（身份提供商仅在发布 JWT 访问令牌时才使用他们）。

## 使用 JWT 授权方授权 API 请求
<a name="http-api-jwt-authorizer.evaluation"></a>

API Gateway 使用以下常规工作流程向配置为使用 JWT 授权方的路由授权请求。

1. 检查 [https://docs.amazonaws.cn/apigatewayv2/latest/api-reference/apis-apiid-authorizers-authorizerid.html#apis-apiid-authorizers-authorizerid-prop-authorizer-identitysource](https://docs.amazonaws.cn/apigatewayv2/latest/api-reference/apis-apiid-authorizers-authorizerid.html#apis-apiid-authorizers-authorizerid-prop-authorizer-identitysource) 是否有令牌。`identitySource` 只能包含令牌或前缀为 `Bearer` 的令牌。

1. 对令牌解码。

1. 使用从发布者的 `jwks_uri` 中提取的公有密钥检查令牌的算法和签名。目前仅支持基于 RSA 的算法。API Gateway 可以将公有密钥缓存两个小时。最佳实践是，在轮换密钥时，留出一段宽限期，在此期间旧密钥和新密钥均有效。

1. 验证声明。API Gateway 评估以下令牌声明：
   +  [https://datatracker.ietf.org/doc/html/rfc7517#section-4.5](https://datatracker.ietf.org/doc/html/rfc7517#section-4.5) – 令牌必须具有与签署令牌的 `jwks_uri` 中的键匹配的标头声明。
   + [https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1) – 必须匹配为授权方配置的 [https://docs.amazonaws.cn/apigatewayv2/latest/api-reference/apis-apiid-authorizers-authorizerid.html#apis-apiid-authorizers-authorizerid-model-jwtconfiguration](https://docs.amazonaws.cn/apigatewayv2/latest/api-reference/apis-apiid-authorizers-authorizerid.html#apis-apiid-authorizers-authorizerid-model-jwtconfiguration)。
   + [https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3) 或 `client_id` – 必须匹配为授权方配置的其中一个 [https://docs.amazonaws.cn/apigatewayv2/latest/api-reference/apis-apiid-authorizers-authorizerid.html#apis-apiid-authorizers-authorizerid-model-jwtconfiguration](https://docs.amazonaws.cn/apigatewayv2/latest/api-reference/apis-apiid-authorizers-authorizerid.html#apis-apiid-authorizers-authorizerid-model-jwtconfiguration) 条目。API Gateway 只有在 `aud` 不存在时才验证 `client_id`。当 `aud` 和 `client_id` 同时存在时，API Gateway 会评估 `aud`。
   + [https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4) – 必须在 UTC 中的当前时间之后。
   + [https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5) – 必须在 UTC 中的当前时间之前。
   + [https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6) – 必须在 UTC 中的当前时间之前。
   + [https://datatracker.ietf.org/doc/html/rfc6749#section-3.3](https://datatracker.ietf.org/doc/html/rfc6749#section-3.3) 或 `scp` – 令牌必须至少包含路由的 [https://docs.amazonaws.cn/apigatewayv2/latest/api-reference/apis-apiid-routes-routeid.html#apis-apiid-routes-routeid-prop-updaterouteinput-authorizationscopes](https://docs.amazonaws.cn/apigatewayv2/latest/api-reference/apis-apiid-routes-routeid.html#apis-apiid-routes-routeid-prop-updaterouteinput-authorizationscopes) 中的一个作用域。

如果这些步骤中的任何一个步骤失败，API Gateway 都会拒绝 API 请求。

验证 JWT 后，API Gateway 将令牌中的声明传递给 API 路由的集成。后端资源（如 Lambda 函数）可以访问 JWT 声明。例如，如果 JWT 包含了身份声明 `emailID`，则它在 `$event.requestContext.authorizer.jwt.claims.emailID` 中可供 Lambda 集成使用。有关 API Gateway 向 Lambda 集成发送的负载的更多信息，请参阅[针对 API Gateway 中的 HTTP API 创建 Amazon Lambda 代理集成](http-api-develop-integrations-lambda.md)。

## 创建 JWT 授权方
<a name="http-api-jwt-authorizer.create"></a>

在创建 JWT 授权方之前，必须向身份提供商注册客户端应用程序。您必须还创建了 HTTP API。有关创建 HTTP API 的示例，请参阅 [创建 HTTP API](http-api-develop.md#http-api-examples)。

### 使用控制台创建 JWT 授权方
<a name="http-api-jwt-authorizer.create.console"></a>

以下步骤说明如何使用控制台创建 JWT 授权方。

**使用控制台创建 JWT 授权方**

1. 通过以下网址登录到 Amazon API Gateway 控制台：[https://console.aws.amazon.com/apigateway](https://console.amazonaws.cn/apigateway)。

1. 选择 HTTP API。

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

1. 选择**管理授权方**选项卡。

1. 选择**创建**。

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

1. 配置您的 JWT 授权方，并指定用于定义令牌来源的**身份来源**。

1. 选择**创建**。

#### 使用 Amazon CLI 创建 JWT 授权方
<a name="http-api-jwt-authorizer.create.cli"></a>

以下 [create-authorizer](https://docs.amazonaws.cn/cli/latest/reference/apigatewayv2/create-authorizer.html) 命令创建 JWT 授权方。对于 `jwt-configuration`，为您的身份提供商指定 `Audience` 和 `Issuer`。如果您使用 Amazon Cognito 作为身份提供者，则 `IssuerUrl` 为 `https://cognito-idp.us-east-2.amazonaws.com/userPoolID`。

```
aws apigatewayv2 create-authorizer \
    --name authorizer-name \
    --api-id api-id \
    --authorizer-type JWT \
    --identity-source '$request.header.Authorization' \
    --jwt-configuration Audience=audience,Issuer=IssuerUrl
```

##### 使用 Amazon CloudFormation 创建 JWT 授权方
<a name="http-api-jwt-cfn.create"></a>

以下 Amazon CloudFormation 模板通过将 Amazon Cognito 用作身份提供者的 JWT 授权方创建 HTTP API。

Amazon CloudFormation 模板的输出是 Amazon Cognito 托管用户界面的 URL，客户可以在其中注册并登录来接收 JWT。客户端登录后，会使用 URL 中的访问令牌将客户端重定向到您的 HTTP API。要使用访问令牌调用 API，请将 URL 中的 `#` 更改为 `?`，来使用该令牌作为查询字符串参数。

##### 示例 Amazon CloudFormation 模板
<a name="http-api-jwt-cfn-example"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Description: |
  Example HTTP API with a JWT authorizer. This template includes an Amazon Cognito user pool as the issuer for the JWT authorizer 
  and an Amazon Cognito app client as the audience for the authorizer. The outputs include a URL for an Amazon Cognito hosted UI where clients can 
  sign up and sign in to receive a JWT. After a client signs in, the client is redirected to your HTTP API with an access token 
  in the URL. To invoke the API with the access token, change the '#' in the URL to a '?' to use the token as a query string parameter.

Resources:
  MyAPI:
    Type: AWS::ApiGatewayV2::Api
    Properties: 
      Description: Example HTTP API
      Name: api-with-auth
      ProtocolType: HTTP
      Target: !GetAtt MyLambdaFunction.Arn
  DefaultRouteOverrides:
    Type: AWS::ApiGatewayV2::ApiGatewayManagedOverrides
    Properties: 
      ApiId: !Ref MyAPI
      Route: 
        AuthorizationType: JWT
        AuthorizerId: !Ref JWTAuthorizer
  JWTAuthorizer:
    Type: AWS::ApiGatewayV2::Authorizer
    Properties: 
      ApiId: !Ref MyAPI
      AuthorizerType: JWT
      IdentitySource: 
        - '$request.querystring.access_token'
      JwtConfiguration: 
        Audience: 
        - !Ref AppClient
        Issuer: !Sub https://cognito-idp.${AWS::Region}.amazonaws.com/${UserPool}
      Name: test-jwt-authorizer
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: nodejs18.x
      Role: !GetAtt FunctionExecutionRole.Arn
      Handler: index.handler
      Code:
        ZipFile: |
          exports.handler = async (event) => {
              const response = {
                  statusCode: 200,
                  body: JSON.stringify('Hello from the ' + event.routeKey + ' route!'),
              };
              return response;
          };
  APIInvokeLambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref MyLambdaFunction
      Action: lambda:InvokeFunction
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MyAPI}/$default/$default
  FunctionExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17		 	 	 '
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      ManagedPolicyArns: 
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      UserPoolName: http-api-user-pool
      AutoVerifiedAttributes:
        - email
      Schema:
        - Name: name
          AttributeDataType: String
          Mutable: true
          Required: true
        - Name: email
          AttributeDataType: String
          Mutable: false
          Required: true
  AppClient:
    Type: AWS::Cognito::UserPoolClient
    Properties:
      AllowedOAuthFlows: 
        - implicit
      AllowedOAuthScopes: 
        - aws.cognito.signin.user.admin
        - email
        - openid
        - profile
      AllowedOAuthFlowsUserPoolClient: true
      ClientName: api-app-client
      CallbackURLs:
        - !Sub https://${MyAPI}.execute-api.${AWS::Region}.amazonaws.com
      ExplicitAuthFlows:
        - ALLOW_USER_PASSWORD_AUTH
        - ALLOW_REFRESH_TOKEN_AUTH
      UserPoolId: !Ref UserPool
      SupportedIdentityProviders:
        - COGNITO 
  HostedUI:
    Type: AWS::Cognito::UserPoolDomain
    Properties: 
      Domain: !Join
        - '-'
        - - !Ref MyAPI
          - !Ref AppClient
      UserPoolId: !Ref UserPool
Outputs:
  SignupURL:
    Value: !Sub https://${HostedUI}.auth.${AWS::Region}.amazoncognito.com/login?client_id=${AppClient}&response_type=token&scope=email+profile&redirect_uri=https://${MyAPI}.execute-api.${AWS::Region}.amazonaws.com
```

## 更新路由来使用 JWT 授权方
<a name="http-api-jwt-authorizer.create.route"></a>

您可以使用控制台、Amazon CLI 或 Amazon SDK 更新路由来使用 JWT 授权方。

### 使用控制台更新路由来使用 JWT 授权方
<a name="http-api-jwt-authorizer.create.route"></a>

以下步骤说明如何使用控制台更新路由来使用 JWT 授权方。

**使用控制台创建 JWT 授权方**

1. 通过以下网址登录到 Amazon API Gateway 控制台：[https://console.aws.amazon.com/apigateway](https://console.amazonaws.cn/apigateway)。

1. 选择 HTTP API。

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

1. 选择一个方法，然后从下拉菜单中选择您的授权方，然后选择**附加授权方**。

#### 使用 Amazon CLI 更新路由来使用 JWT 授权方
<a name="http-api-jwt-authorizer.create.route"></a>

以下 [update-route](https://docs.amazonaws.cn/cli/latest/reference/apigatewayv2/update-route.html) 命令更新路由以使用 JWT 授权方：

```
aws apigatewayv2 update-route \
   --api-id api-id  \
   --route-id route-id  \
   --authorization-type JWT \
   --authorizer-id authorizer-id \
   --authorization-scopes user.email
```

# 在 API Gateway 中使用 IAM 授权来控制对 HTTP API 的访问
<a name="http-api-access-control-iam"></a>

您可以为 HTTP API 路由启用 IAM 授权。启用 IAM 授权后，客户端必须使用[签名版本 4（SigV4）](https://docs.amazonaws.cn/IAM/latest/UserGuide/reference_sigv.html)，才能使用 Amazon 凭证签署其请求。仅当客户端对路由具有 `execute-api` 权限时，API Gateway 才会调用您的 API 路由。

用于 HTTP API 的 IAM 授权类似于用于 [REST API](api-gateway-control-access-using-iam-policies-to-invoke-api.md) 的授权。

**注意**  
HTTP API 目前不支持资源策略。

有关授予客户端调用 API 的 IAM 权限的策略示例，请参阅 [针对调用 API 的访问控制](api-gateway-control-access-using-iam-policies-to-invoke-api.md)。

## 为路由启用 IAM 授权
<a name="http-api-access-control-iam-example"></a>

以下 [update-route](https://docs.amazonaws.cn/cli/latest/reference/apigatewayv2/update-route.html) 命令为 HTTP API 路由启用 IAM 授权:

```
aws apigatewayv2 update-route \
    --api-id abc123 \
    --route-id abcdef \
    --authorization-type AWS_IAM
```