

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 自定义身份验证和授权
<a name="custom-authentication"></a>

 AWS IoT Core 允许您定义自定义授权方，以便您可以管理自己的客户端身份验证和授权。当您需要使用 AWS IoT Core 原生支持的身份验证机制以外的身份验证机制时，这很有用。（有关本地支持机制的更多信息，请参阅 [客户端身份验证](client-authentication.md)）。  

 例如，如果您要将现场现有设备迁移到， AWS IoT Core 并且这些设备使用自定义不记名令牌或 MQTT 用户名和密码进行身份验证，则 AWS IoT Core 无需为其配置新身份即可将其迁移到。您可以对任何 AWS IoT Core 支持的通信协议使用自定义身份验证。有关受 AWS IoT Core 支持的协议的更多信息，请参阅 [设备通信协议](protocols.md)。

**Topics**
+ [了解自定义身份验证工作流](custom-authorizer.md)
+ [创建和管理自定义授权方（CLI）](config-custom-auth.md)
+ [使用 X.509 客户端证书进行自定义身份验证](custom-auth-509cert.md)
+ [使用自定义身份验证 AWS IoT Core 进行连接](custom-auth.md)
+ [授权方故障排除](custom-auth-troubleshooting.md)

# 了解自定义身份验证工作流
<a name="custom-authorizer"></a>

自定义身份验证使您能够定义如何通过使用[授权方资源](https://docs.aws.amazon.com/iot/latest/apireference/API_AuthorizerDescription.html)对客户端进行身份验证和授权。  每个授权方都包含对客户托管的 Lambda 函数的引用、用于验证设备凭证的可选公有密钥以及其它配置信息。下图说明了 AWS IoT Core中自定义身份验证的授权工作流。

![\[AWS IoT Core中的自定义身份验证的自定义授权工作流。\]](http://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/images/custom-authentication.png)


## AWS IoT Core 自定义身份验证和授权工作流程
<a name="custom-authentication-workflow"></a>

下面的列表说明了自定义身份验证和授权工作流中的每个步骤。

1. 设备使用支持的终端连接到客户 AWS IoT Core 的数据端点[设备通信协议](protocols.md)。设备在请求的标头字段或查询参数（针对基于协议的 HTTP 发布或 MQTT），或者在 MQTT CONNECT 消息的用户名和密码字段（适用于 WebSockets 协议上的 MQTT 和 MQTT）中传递凭证。 WebSockets 

1. AWS IoT Core 检查以下两个条件之一：
   + 传入的请求指定授权方。
   + 接收请求 AWS IoT Core 的数据端点已为其配置了默认授权方。

   如果通过上述任一方式 AWS IoT Core 找到授权方，则 AWS IoT Core 会触发与授权方关联的 Lambda 函数。

1.  （可选）如果您已启用令牌签名，则在触发 Lambda 函数之前，使用存储在授权方中的公钥来 AWS IoT Core 验证请求签名。如果验证失败， AWS IoT Core 将停止请求而不调用 Lambda 函数。  

1. Lambda 函数接收请求中的凭证和连接元数据，并做出身份验证决策。

1. Lambda 函数返回身份验证决策的结果和一份指定连接中允许执行哪些操作的 AWS IoT Core 策略文档。 Lambda 函数还会返回信息，指定通过调用 Lambda 函数 AWS IoT Core 重新验证请求中的证书的频率。

1. AWS IoT Core 根据连接从 Lambda 函数收到的策略评估连接上的活动。

1. 在建立连接并首次调用您的自定义授权方 Lambda 之后，空闲连接上的下一次调用可能会延迟最多 5 分钟，且不执行任何 MQTT 操作。之后，后续调用将遵循您的自定义授权方 Lambda 中的刷新间隔。这种方法可以防止可能超过您的 Lambda 并发限制的过度调用。 AWS 账户

## 扩展注意事项
<a name="custom-authentication-scaling"></a>

 由于 Lambda 函数为您的授权方处理身份验证和授权，因此该函数受 Lambda 定价和服务限制的约束，例如并发执行率。有关 Lambda 定价的更多信息，请参阅 [Lambda 定价](https://aws.amazon.com/lambda/pricing/)。您可以通过调整 Lambda 函数响应中的 `refreshAfterInSeconds` 和 `disconnectAfterInSeconds` 参数管理您 Lambda 函数上的有效载荷。有关 Lambda 函数响应内容的更多信息，请参阅 [定义您的 Lambda 函数](custom-auth-lambda.md)。

**注意**  
如果启用签名，则可以防止无法识别的客户端过度触发 Lambda。在禁用授权方的签名之前，请考虑这一点。

**注意**  
自定义授权方的 Lambda 函数超时限制为 5 秒。

# 创建和管理自定义授权方（CLI）
<a name="config-custom-auth"></a>

AWS IoT Core 使用自定义授权方实现自定义身份验证和授权方案。自定义授权者是一种 AWS IoT Core 资源，可让您灵活地根据自己的特定要求定义和实施规则和策略。要使用 step-by-step说明创建自定义授权方，请参阅[教程：为创建自定义授权方](https://docs.aws.amazon.com//iot/latest/developerguide/custom-auth-tutorial.html)。 AWS IoT Core

各授权方均包括以下组件：
+  *名称*：用户定义的唯一字符串，用于标识授权方。
+  *Lambda 函数 ARN*：Lambda 函数的 Amazon 资源名称（ARN），用于实现授权和身份验证逻辑。  
+  *令牌密钥名称*：用于从 HTTP 标头、查询参数或 MQTT CONNECT 用户名中提取令牌以执行签名验证的键名称。如果在授权方中启用了签名，则需要此值。
+  *签名禁用标志（可选）*：指定是否禁用凭证签名要求的布尔值。这对于签名凭证没有意义的情况非常有用，例如使用 MQTT 用户名和密码的身份验证方案。默认值为 `false`，因此默认情况下签名将处于启用状态。
+  *令牌签名公有密钥*： AWS IoT Core 用于验证令牌签名的公有密钥。其最小长度为 2048 位。如果在授权方中启用了签名，则需要此值。  

Lambda 将根据 Lambda 函数的运行次数以及函数中代码执行所需的时间向您收取费用。有关 Lambda 定价的更多信息，请参阅 [Lambda 定价](https://aws.amazon.com/lambda/pricing/)。有关创建 Lambda 函数的更多信息，请参阅 [Lambda 开发人员指南](https://docs.aws.amazon.com/lambda/latest/dg/)。

**注意**  
如果启用签名，则可以防止无法识别的客户端过度触发 Lambda。在禁用授权方的签名之前，请考虑这一点。

**注意**  
自定义授权方的 Lambda 函数超时限制为 5 秒。

**Topics**
+ [定义您的 Lambda 函数](custom-auth-lambda.md)
+ [创建授权方](custom-auth-create-authorizer.md)
+ [授权调用您 AWS IoT 的 Lambda 函数](custom-auth-authorize.md)
+ [测试授权方](custom-auth-testing.md)
+ [管理自定义授权方](custom-auth-manage.md)

# 定义您的 Lambda 函数
<a name="custom-auth-lambda"></a>

 当 AWS IoT Core 调用您的授权方时，它会使用包含以下 JSON 对象的事件触发与授权方关联的 Lambda。示例 JSON 对象包含所有可能的字段。不包括与连接请求无关的任何字段。

```
{
    "token" :"aToken",
    "signatureVerified": Boolean, // Indicates whether the device gateway has validated the signature.
    "protocols": ["tls", "http", "mqtt"], // Indicates which protocols to expect for the request.
    "protocolData": {
        "tls" : {
            "serverName": "serverName" // The server name indication (SNI) host_name string.
        },
        "http": {
            "headers": {
                "#{name}": "#{value}"
            },
            "queryString": "?#{name}=#{value}"
        },
        "mqtt": {
            "username": "myUserName",
            "password": "myPassword", // A base64-encoded string.
            "clientId": "myClientId" // Included in the event only when the device sends the value.
        }
    },
    "connectionMetadata": {
        "id": UUID // The connection ID. You can use this for logging.
    },
}
```

 Lambda 函数应使用此信息对传入连接进行身份验证，并决定允许在连接中执行哪些操作。函数应发送包含以下值的响应。
+  `isAuthenticated`：一个布尔值，指示是否已对请求进行身份验证。
+  `principalId`：字母数字字符串，它充当自定义授权请求发送的令牌的标识符。该值必须是包含至少一个字符且不超过 128 个字符的字母数字字符串，并与此正则表达式（正则表达式）模式匹配：`([a-zA-Z0-9]){1,128}`。不允许在 in `principalId` 中 AWS IoT Core使用非字母数字的特殊字符。如果允许使用非字母数字特殊字符，请参阅其他 AWS 服务的文档。`principalId`
+  `policyDocuments`：JSON 格式的 AWS IoT Core 策略文档列表有关创建 AWS IoT Core 策略的更多信息，请参阅。[AWS IoT Core 政策](iot-policies.md)策略文档的数量最多为 10 个。每个策略文档最多可以包含 2048 个字符。
+  `disconnectAfterInSeconds`：指定与 AWS IoT Core 网关的连接的最大持续时间（以秒为单位）的整数。最小值为 300 秒，最大值为 86400 秒。默认值是 86,400。
**注意**  
`disconnectAfterInSeconds` 的值（由 Lambda 函数返回）在建立连接时设置。在后续策略刷新 Lambda 调用过程中，将无法修改此值。
+  `refreshAfterInSeconds`：指定策略刷新之间间隔的整数。当此时间间隔过去时， AWS IoT Core 将调用 Lambda 函数以允许策略刷新。最小值为 300 秒，最大值为 86400 秒。

  以下 JSON 对象包含 Lambda 函数可以发送的响应示例。

 **\$1 "isAuthenticated":true, //A Boolean that determines whether client can connect. "principalId": "xxxxxxxx",  //A string that identifies the connection in logs. "disconnectAfterInSeconds": 86400,  "refreshAfterInSeconds": 300,   "policyDocuments": [       \$1         "Version": "2012-10-17",         "Statement": [            \$1               "Action": "iot:Publish",               "Effect": "Allow",               "Resource": "arn:aws:iot:us-east-1:<your\$1aws\$1account\$1id>:topic/customauthtesting"             \$1          ]        \$1     ] \$1**

 该`policyDocument`值必须包含有效的 AWS IoT Core 策略文档。有关 AWS IoT Core 策略的更多信息，请参阅[AWS IoT Core 政策](iot-policies.md)。 在 TLS 上的 MQTT 和通过 WebSockets连接的 MQ AWS IoT Core TT 中，在字段值中指定的间隔内缓存此策略。`refreshAfterInSeconds`在 HTTP 连接的情况下，每个授权请求都会调用 Lambda 函数，除非您的设备使用 HTTP 持久连接（也称为 HTTP 保持活动状态或 HTTP 连接重用），否则您可以在配置授权方时选择启用缓存。在此间隔内， AWS IoT Core 授权在已建立的连接中针对此缓存策略执行操作，而无需再次触发您的 Lambda 函数。如果在自定义身份验证期间出现故障，则 AWS IoT Core 终止连接。 AWS IoT Core 如果连接的打开时间超过`disconnectAfterInSeconds`参数中指定的值，也会终止该连接。

 以下内容 JavaScript 包含一个 Node.js Lambda 函数示例，该函数在 MQTT Connect 消息中查找值为`test`的密码，并返回一个策略，该策略授予使用`myClientName`名为的客户端进行连接 AWS IoT Core 并发布到包含相同客户端名称的主题的权限。如果未找到预期密码，则返回拒绝这两个操作的策略。

```
// A simple Lambda function for an authorizer. It demonstrates 
// how to parse an MQTT password and generate a response.

exports.handler = function(event, context, callback) { 
    var uname = event.protocolData.mqtt.username;
    var pwd = event.protocolData.mqtt.password;
    var buff = new Buffer(pwd, 'base64');
    var passwd = buff.toString('ascii');
    switch (passwd) { 
        case 'test': 
            callback(null, generateAuthResponse(passwd, 'Allow')); 
            break;
        default: 
            callback(null, generateAuthResponse(passwd, 'Deny'));  
    }
};

// Helper function to generate the authorization response.
var generateAuthResponse = function(token, effect) { 
    var authResponse = {}; 
    authResponse.isAuthenticated = true; 
    authResponse.principalId = 'TEST123'; 
    
    var policyDocument = {}; 
    policyDocument.Version = '2012-10-17';		 	 	 
    policyDocument.Statement = []; 
    var publishStatement = {}; 
    var connectStatement = {};
    connectStatement.Action = ["iot:Connect"];
    connectStatement.Effect = effect;
    connectStatement.Resource = ["arn:aws:iot:us-east-1:123456789012:client/myClientName"];
    publishStatement.Action = ["iot:Publish"]; 
    publishStatement.Effect = effect; 
    publishStatement.Resource = ["arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"]; 
    policyDocument.Statement[0] = connectStatement;
    policyDocument.Statement[1] = publishStatement; 
    authResponse.policyDocuments = [policyDocument]; 
    authResponse.disconnectAfterInSeconds = 3600; 
    authResponse.refreshAfterInSeconds = 300;
    
    return authResponse; 
}
```

 上述 Lambda 函数在收到 MQTT Connect 消息中的预期密码 `test` 时返回以下 JSON。`password` 和 `principalId` 属性的值将是来自 MQTT Connect 消息的值。

```
{
  "password": "password",
  "isAuthenticated": true,
  "principalId": "principalId",
  "policyDocuments": [
    {
      "Version": "2012-10-17",		 	 	 
      "Statement": [
        {
          "Action": "iot:Connect",
          "Effect": "Allow",
          "Resource": "*"
        },
        {
          "Action": "iot:Publish",
          "Effect": "Allow",
          "Resource": "arn:aws:iot:region:accountId:topic/telemetry/${iot:ClientId}"
        },
        {
          "Action": "iot:Subscribe",
          "Effect": "Allow",
          "Resource": "arn:aws:iot:region:accountId:topicfilter/telemetry/${iot:ClientId}"
        },
        {
          "Action": "iot:Receive",
          "Effect": "Allow",
          "Resource": "arn:aws:iot:region:accountId:topic/telemetry/${iot:ClientId}"
        }
      ]
    }
  ],
  "disconnectAfterInSeconds": 3600,
  "refreshAfterInSeconds": 300
}
```

# 创建授权方
<a name="custom-auth-create-authorizer"></a>

 您可以使用 [CreateAuthorizerAP](https://docs.aws.amazon.com/iot/latest/apireference/API_CreateAuthorizer.html) I 创建授权方。 以下示例描述了该命令。

```
aws iot create-authorizer
--authorizer-name MyAuthorizer
--authorizer-function-arn arn:aws:lambda:us-west-2:<account_id>:function:MyAuthorizerFunction  //The ARN of the Lambda function.
[--token-key-name MyAuthorizerToken //The key used to extract the token from headers.
[--token-signing-public-keys FirstKey=
 "-----BEGIN PUBLIC KEY-----
  [...insert your public key here...] 
  -----END PUBLIC KEY-----"
[--status ACTIVE]
[--tags <value>]
[--signing-disabled | --no-signing-disabled]
```

您可以使用 `signing-disabled` 参数选择退出适用于授权方的每次调用的签名验证。除有必要，否则我们强烈建议您不要禁用签名。签名验证可防止来自未知设备的 Lambda 函数过多调用。您无法在创建授权方后更新其 `signing-disabled` 状态。要更改此行为，您必须创建 `signing-disabled` 参数具有不同值的其它自定义授权方。

如果您已禁用签名，则 `tokenKeyName` 和 `tokenSigningPublicKeys` 参数的值是可选的。如果启用了签名，则它们是必需的值。

创建 Lambda 函数和自定义授权方后，必须明确授予 AWS IoT Core 服务权限才能代表您调用该函数。 您可以使用以下命令执行此操作。

**注意**  
默认的物联网端点可能不支持将自定义授权方与 Lambda 函数一起使用。相反，您可以使用域配置来定义新端点，然后为该自定义授权方指定该端点。

```
aws lambda add-permission --function-name <lambda_function_name>
--principal iot.amazonaws.com --source-arn <authorizer_arn>
--statement-id Id-123 --action "lambda:InvokeFunction"
```

# 授权调用您 AWS IoT 的 Lambda 函数
<a name="custom-auth-authorize"></a>

在本节中，您将为您刚创建的自定义授权方资源授予运行 Lambda 函数的权限。要授予权限，您可以使用 [add-permission](https://docs.aws.amazon.com//cli/latest/reference/lambda/add-permission.html) CLI 命令。

**使用授予您的 Lambda 函数的权限 AWS CLI**

1. 插入您的值后，输入以下命令。请注意，`statement-id` 值必须唯一。将 `Id-1234` 替换为您的确切值，否则，可能会出现 `ResourceConflictException` 错误。

   ```
   aws lambda add-permission  \
   --function-name "custom-auth-function" \
   --principal "iot.amazonaws.com" \
   --action "lambda:InvokeFunction" \
   --statement-id "Id-1234" \
   --source-arn authorizerArn
   ```

1. 如果命令成功，则返回一个权限语句，如本示例。您可以继续到下一部分来测试自定义授权方。

   ```
   {
       "Statement": "{\"Sid\":\"Id-1234\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"iot.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function\"}}}"
   }
   ```

   如果命令不成功，则返回错误，如本示例。在继续操作之前，您需要查看并更正错误。

   ```
   An error occurred (AccessDeniedException) when calling the AddPermission operation: User: arn:aws:iam::57EXAMPLE833:user/EXAMPLE-1 is not authorized to perform: lambda:AddPer
   mission on resource: arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function
   ```

# 测试授权方
<a name="custom-auth-testing"></a>

 您可以使用 [TestInvokeAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_TestInvokeAuthorizer.html)API 来测试授权方的调用和返回值。 此 API 使您能够在授权方中指定协议元数据并测试签名验证。

以下选项卡显示了如何使用 AWS CLI 来测试您的授权者。

------
#### [ Unix-like ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER \
--token TOKEN_VALUE --token-signature TOKEN_SIGNATURE
```

------
#### [ Windows CMD ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER ^
--token TOKEN_VALUE --token-signature TOKEN_SIGNATURE
```

------
#### [ Windows PowerShell ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER `
--token TOKEN_VALUE --token-signature TOKEN_SIGNATURE
```

------

`token-signature` 参数的值是签名令牌。要了解如何获取此值，请参阅 [签名令牌](custom-auth.md#custom-auth-token-signature)。

如果您的授权方使用了用户名和密码，您可以使用 `--mqtt-context` 参数传递此信息。以下选项卡显示如何使用 `TestInvokeAuthorizer` API 将包含用户名、密码和客户端名称的 JSON 对象发送到您的自定义授权方。

------
#### [ Unix-like ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER  \
--mqtt-context '{"username": "USER_NAME", "password": "dGVzdA==", "clientId":"CLIENT_NAME"}'
```

------
#### [ Windows CMD ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER  ^
--mqtt-context '{"username": "USER_NAME", "password": "dGVzdA==", "clientId":"CLIENT_NAME"}'
```

------
#### [ Windows PowerShell ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER  `
--mqtt-context '{"username": "USER_NAME", "password": "dGVzdA==", "clientId":"CLIENT_NAME"}'
```

------

密码必须采用 base64 编码。以下示例说明如何在类 Unix 的环境中对密码进行编码。

```
echo -n PASSWORD | base64
```

# 管理自定义授权方
<a name="custom-auth-manage"></a>

 您可以使用以下 APIs方法来管理您的授权者。
+ [ListAuthorizers](https://docs.aws.amazon.com/iot/latest/apireference/API_ListAuthorizers.html): 显示您账户中的所有授权人。
+  [DescribeAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_DescribeAuthorizer.html)：显示指定授权者的属性。这些值包括创建日期、上次修改日期和其它属性。
+ [SetDefaultAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_SetDefaultAuthorizer.html)：为您的 AWS IoT Core 数据端点指定默认授权方。 AWS IoT Core 如果设备未通过 AWS IoT Core 凭证且未指定授权方，则使用此授权方。有关使用 AWS IoT Core 证书的更多信息，请参阅[客户端身份验证](client-authentication.md)。
+ [UpdateAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_UpdateAuthorizer.html)：更改指定授权方的状态、令牌密钥名称或公钥。
+  [DeleteAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_DeleteAuthorizer.html)：删除指定的授权者。

**注意**  
 您无法更新授权方的签名要求。这意味着您无法禁用需要签名的现有授权方的中签名。您也不能在不需要签名的现有授权方中要求签名。

# 使用 X.509 客户端证书进行自定义身份验证
<a name="custom-auth-509cert"></a>

将设备连接到时 AWS IoT Core，您有多种[身份验证类型](protocols.md#connection-protocol-auth-mode)可用。您可以使用可用于对客户端和设备连接进行身份验证的 [X.509 客户端证书](https://docs.aws.amazon.com//iot/latest/developerguide/x509-client-certs.html)，也可以定义[自定义授权方](https://docs.aws.amazon.com//iot/latest/developerguide/custom-authentication.html)来管理自己的客户端身份验证和授权逻辑。本主题介绍如何使用 X.509 客户端证书进行自定义身份验证。

如果您已经使用 X.509 证书对设备进行了身份验证，并且想要执行额外的验证和自定义授权，则使用 X.509 证书进行自定义身份验证会很有帮助。例如，如果您将设备的数据（例如序列号）存储在 X.509 客户端证书中，则在对 X.509 客户端证书 AWS IoT Core 进行身份验证后，您可以使用自定义授权方根据证书字段中存储的信息来识别特定设备。 CommonName 将自定义身份验证与 X.509 证书配合使用可以增强设备在连接设备时的安全管理，并为管理身份验证 AWS IoT Core 和授权逻辑提供更大的灵活性。 AWS IoT Core [https://docs.aws.amazon.com//iot/latest/developerguide/mqtt.html](https://docs.aws.amazon.com//iot/latest/developerguide/mqtt.html)有关 AWS IoT Core 设备端点支持的身份验证类型和应用程序协议的更多信息，请参阅[设备通信协议](https://docs.aws.amazon.com//iot/latest/developerguide/protocols.html)。

**注意**  
各区域不支持使用 X.509 客户端证书进行自定义身份验证。 AWS GovCloud (US) 

**重要**  
您必须使用通过[域配置](iot-custom-endpoints-configurable.md)创建的端点。此外，客户端在连接到时必须提供[服务器名称指示 (SNI)](https://www.rfc-editor.org/rfc/rfc3546#section-3.1) 扩展名。 AWS IoT Core

**Topics**
+ [第 1 步：使用注册您的 X.509 客户端证书 AWS IoT Core](#custom-auth-509cert-client)
+ [第 2 步：创建 Lambda 函数](#custom-auth-509cert-lambda)
+ [步骤 3：创建自定义授权方](#custom-auth-509cert-authorizer)
+ [步骤 4：在域配置中设置身份验证类型和应用程序协议](#custom-auth-509cert-domainconfig)

## 第 1 步：使用注册您的 X.509 客户端证书 AWS IoT Core
<a name="custom-auth-509cert-client"></a>

如果您尚未执行此操作，请使用注册并激活您的 [X.509 客户端证书](https://docs.aws.amazon.com//iot/latest/developerguide/x509-client-certs.html)。 AWS IoT Core否则，请跳到下一步。

要使用注册和激活您的客户端证书 AWS IoT Core，请按照以下步骤操作：

1. 如果您[直接使用创建客户证书 AWS IoT](https://docs.aws.amazon.com//iot/latest/developerguide/device-certs-create.html)。这些客户证书将自动向注册 AWS IoT Core。

1. 如果您[创建自己的客户证书](https://docs.aws.amazon.com//iot/latest/developerguide/device-certs-your-own.html)，请按照[以下说明进行注册 AWS IoT Core](https://docs.aws.amazon.com//iot/latest/developerguide/register-device-cert.html)。

1. 要激活您的客户端证书，请按照[以下说明](https://docs.aws.amazon.com//iot/latest/developerguide/activate-or-deactivate-device-cert.html)进行操作。

## 第 2 步：创建 Lambda 函数
<a name="custom-auth-509cert-lambda"></a>

AWS IoT Core 使用自定义授权方来实现自定义身份验证和授权方案。自定义授权方与 Lambda 函数相关联，该函数确定设备是否经过身份验证以及允许该设备执行哪些操作。当设备连接到时，会 AWS IoT Core 检索授权方详细信息 AWS IoT Core，包括授权方名称和关联的 Lambda 函数，并调用 Lambda 函数。Lambda 函数会收到一个事件，其中包含一个 JSON 对象以及设备的 X.509 客户端证书数据。您的 Lambda 函数使用此事件 JSON 对象来评估身份验证请求、决定要采取的操作并发回响应。

### Lambda 函数事件示例
<a name="custom-auth-509cert-event"></a>

以下示例 JSON 对象包含可以包含的所有可能字段。实际的 JSON 对象将仅包含与特定连接请求相关的字段。

```
{
	"token": "aToken",
	"signatureVerified": true,
	"protocols": [
		"tls",
		"mqtt"
	],
	"protocolData": {
		"tls": {
			"serverName": "serverName",
			"x509CertificatePem": "x509CertificatePem",
			"principalId": "principalId"
		},
		"mqtt": {
			"clientId": "myClientId",
                     "username": "myUserName",
                     "password": "myPassword"
		}
	},
	"connectionMetadata": {
		"id": "UUID"
	}
}
```

`signatureVerified`  
一个布尔值，用于指示在调用授权方的 Lambda 函数之前是否验证了在授权方配置的令牌签名。如果授权方配置为禁用令牌签名，则此字段将为 false。

`protocols`  
包含请求预期协议的数组。

`protocolData`  
包含连接中所使用的协议信息的对象。它提供了特定于协议的详细信息，对于身份验证、授权等非常有用。  
`tls` - 此对象包含与 TLS（传输层安全性）协议相关的信息。  
+ `serverName` - [服务器名称指示（SNI）](https://www.rfc-editor.org/rfc/rfc3546#section-3.1)主机名字符串。 AWS IoT Core 要求设备将 [SNI 扩展](https://www.rfc-editor.org/rfc/rfc3546#section-3.1)发送到传输层安全性（TLS）协议，并在 `host_name` 字段中提供完整的端点地址。
+ `x509CertificatePem` - PEM 格式的 X.509 证书，用于在 TLS 连接中进行客户端身份验证。
+ `principalId` - 在 TLS 连接中与客户端关联的主体标识符。
`mqtt` - 此对象保存与 MQTT 协议相关的信息。  
+ `clientId` - 只有在设备发送该值的事件中才需要包含的一个字符串。
+ `username` - MQTT Connect 数据包中提供的用户名。
+ `password` - MQTT Connect 数据包中提供的密码。

`connectionMetadata`  
连接的元数据。  
`id` - 连接 ID，可用于日志记录和故障排除。

**注意**  
在本事件 JSON 对象中，`x509CertificatePem` 和 `principalId` 是请求中的两个新字段。`principalId` 的值与 `certificateId` 的值相同。有关更多信息，请参阅[证书](https://docs.aws.amazon.com//iot/latest/apireference/API_Certificate.html)。

### Lambda 函数响应示例
<a name="custom-auth-509cert-response"></a>

Lambda 函数应使用来自事件 JSON 对象的信息，对传入连接进行身份验证，并决定允许在连接中执行哪些操作。

以下 JSON 对象包含 Lambda 函数可以发送的响应示例。

```
{
	"isAuthenticated": true,
	"principalId": "xxxxxxxx",
	"disconnectAfterInSeconds": 86400,
	"refreshAfterInSeconds": 300,
	"policyDocuments": [
		{
			"Version": "2012-10-17",		 	 	 
			"Statement": [
				{
					"Effect": "Allow",
					"Action": "iot:Publish",
					"Resource": "arn:aws:iot:us-east-1:123456789012:topic/customauthtesting"
				}
			]
		}
	]
}
```

在本示例中，该函数应发送包含以下值的响应。

`isAuthenticated`  
一个布尔值，指示是否已对请求进行身份验证。

`principalId`  
一个字母数字字符串，它充当自定义授权请求发送的令牌的标识符。该值必须是包含至少一个字符且不超过 128 个字符的字母数字字符串。它在日志中标识连接。`principalId` 的值必须与事件 JSON 对象中的 `principalId` 的值相同（即 X.509 证书的 certificateId）。

`policyDocuments`  
JSON 格式的 AWS IoT Core 策略文件列表。该值是可选的，支持[事物策略变量](https://docs.aws.amazon.com//iot/latest/developerguide/thing-policy-variables.html)和[证书策略变量](https://docs.aws.amazon.com//iot/latest/developerguide/cert-policy-variables.html)。策略文档的数量最多为 10 个。每个策略文档最多可以包含 2048 个字符。如果您的客户端证书和 Lambda 函数附加了多个策略，则该权限是所有策略的集合。有关创建 AWS IoT Core 策略的更多信息，请参阅[策略](https://docs.aws.amazon.com//iot/latest/developerguide/iot-policies.html)。

`disconnectAfterInSeconds`  
一个整数，它指定 AWS IoT Core 网关连接的最大持续时间（以秒为单位）。最小值为 300 秒，最大值为 86400 秒。`disconnectAfterInSeconds` 在连接的生命周期内有效，连续刷新策略时不会刷新。

`refreshAfterInSeconds`  
指定策略刷新之间间隔的整数。此间隔过后， AWS IoT Core 调用 Lambda 函数以允许刷新策略。最小值为 300 秒，最大值为 86400 秒。

### 示例 Lambda 函数
<a name="custom-auth-509cert-js-example"></a>

下面是一个 Node.js Lambda 函数示例。该函数检查客户端的 X.509 证书并提取相关信息，例如序列号、指纹和主题名称。如果提取的信息与预期值相匹配，则授予客户端连接访问权限。此机制可确保只有拥有有效证书的授权客户端才能建立连接。

```
const crypto = require('crypto');

exports.handler = async (event) => {
    
    // Extract the certificate PEM from the event
    const certPem = event.protocolData.tls.x509CertificatePem;
    
    // Parse the certificate using Node's crypto module
    const cert = new crypto.X509Certificate(certPem);
    
    var effect = "Deny";
    // Allow permissions only for a particular certificate serial, fingerprint, and subject
    if (cert.serialNumber === "7F8D2E4B9C1A5036DE8F7C4B2A91E5D80463BC9A1257" // This is a random serial
       && cert.fingerprint === "F2:9A:C4:1D:B5:E7:08:3F:6B:D0:4E:92:A7:C1:5B:8D:16:0F:E3:7A" // This is a random fingerprint
       && cert.subject === "allow.example.com") {
      effect = "Allow";
    }
    
    return generateAuthResponse(event.protocolData.tls.principalId, effect);
};


// Helper function to generate the authorization response.
function generateAuthResponse(principalId, effect) {
    const authResponse = {
        isAuthenticated: true,
        principalId,
        disconnectAfterInSeconds: 3600,
        refreshAfterInSeconds: 300,
        policyDocuments: [
          {
            Version: "2012-10-17",		 	 	 
            Statement: [
              {
                Action: ["iot:Connect"],
                Effect: effect,
                Resource: [
                  "arn:aws:iot:us-east-1:123456789012:client/myClientName"
                ]
              },
              {
                Action: ["iot:Publish"],
                Effect: effect,
                Resource: [
                  "arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"
                ]
              },
              {
                Action: ["iot:Subscribe"],
                Effect: effect,
                Resource: [
                   "arn:aws:iot:us-east-1:123456789012:topicfilter/telemetry/myClientName"
                ]
              },
              {
                Action: ["iot:Receive"],
                Effect: effect,
                Resource: [
                   "arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"
                ]
              }
            ]
          }
        ]
      };

  return authResponse;
}
```

上述 Lambda 函数在收到包含预期序列号、指纹和主题的证书时返回以下 JSON。`x509CertificatePem` 的值将是 TLS 握手中提供的客户端证书。有关更多信息，请参阅[定义 Lambda 函数](https://docs.aws.amazon.com//iot/latest/developerguide/config-custom-auth.html#custom-auth-lambda)。

```
{
	"isAuthenticated": true,
	"principalId": "principalId in the event JSON object",
	"policyDocuments": [
		{
			"Version": "2012-10-17",		 	 	 
			"Statement": [
				{
					"Action": "iot:Connect",
					"Effect": "Allow",
					"Resource": "arn:aws:iot:us-east-1:123456789012:client/myClientName"
				},
				{
					"Action": "iot:Publish",
					"Effect": "Allow",
					"Resource": "arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"
				},
				{
					"Action": "iot:Subscribe",
					"Effect": "Allow",
					"Resource": "arn:aws:iot:us-east-1:123456789012:topicfilter/telemetry/myClientName"
				},
				{
					"Action": "iot:Receive",
					"Effect": "Allow",
					"Resource": "arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"
				}
			]
		}
	],
	"disconnectAfterInSeconds": 3600,
	"refreshAfterInSeconds": 300
}
```

## 步骤 3：创建自定义授权方
<a name="custom-auth-509cert-authorizer"></a>

[定义 Lambda 函数](#custom-auth-509cert-lambda)后，创建自定义授权方来管理您自己的客户端身份验证和授权逻辑。您可以按照[步骤 3：创建客户授权方资源及其授权](https://docs.aws.amazon.com//iot/latest/developerguide/custom-auth-tutorial.html#custom-auth-tutorial-authorizer)中的详细说明进行操作。有关更多信息，请参阅[创建授权方](https://docs.aws.amazon.com//iot/latest/developerguide/config-custom-auth.html)。

在创建自定义授权方的过程中，您必须授予 AWS IoT 在创建 Lambda 函数后调用该函数的权限。有关详细说明，请参阅[授权 AWS IoT 调用 Lambda](custom-auth-authorize.md) 函数。

## 步骤 4：在域配置中设置身份验证类型和应用程序协议
<a name="custom-auth-509cert-domainconfig"></a>

要结合 X.509 客户端证书使用自定义身份验证对设备进行身份验证，必须在域配置中设置身份验证类型和应用程序协议，并且必须发送 SNI 扩展。`authenticationType` 的值必须为 `CUSTOM_AUTH_X509`，`applicationProtocol` 的值可以是 `SECURE_MQTT` 或 `HTTPS`。

### 在域配置中设置身份验证类型和应用程序协议（CLI）
<a name="custom-auth-509cert-cli"></a>

如果您没有域配置，请使用 [https://docs.aws.amazon.com//cli/latest/reference/iot/create-domain-configuration.html](https://docs.aws.amazon.com//cli/latest/reference/iot/create-domain-configuration.html) 命令创建一个。`authenticationType` 的值必须为 `CUSTOM_AUTH_X509`，`applicationProtocol` 的值可以是 `SECURE_MQTT` 或 `HTTPS`。

```
aws iot create-domain-configuration \
    --domain-configuration-name domainConfigurationName \
    --authentication-type CUSTOM_AUTH_X509 \  
    --application-protocol SECURE_MQTT \ 
    --authorizer-config '{
        "defaultAuthorizerName": my-custom-authorizer
    }'
```

如果您已经有域配置，请根据需要使用 [https://docs.aws.amazon.com//cli/latest/reference/iot/update-domain-configuration.html](https://docs.aws.amazon.com//cli/latest/reference/iot/update-domain-configuration.html) 命令更新 `authenticationType` 和 `applicationProtocol`。请注意，您不能更改默认端点 (`iot:Data-ATS`) 上的身份验证类型或协议。

```
aws iot update-domain-configuration \
    --domain-configuration-name domainConfigurationName \
    --authentication-type CUSTOM_AUTH_X509 \  
    --application-protocol SECURE_MQTT \
    --authorizer-config '{
        "defaultAuthorizerName": my-custom-authorizer
    }'
```

`domain-configuration-name`  
域配置的名称。

`authentication-type`  
域配置的身份验证类型。有关更多信息，请参阅[选择身份验证类型](protocols.md#connection-protocol-auth-mode)。

`application-protocol`  
设备用来与 AWS IoT Core进行通信的应用程序协议。有关更多信息，请参阅[选择应用程序协议](protocols.md#protocol-selection)。

`--authorizer-config`  
指定域配置中的授权方配置的对象。

`defaultAuthorizerName`  
域配置的授权方的名称。

有关更多信息，请参阅 *AWS IoT API 参考[UpdateDomainConfiguration](https://docs.aws.amazon.com//iot/latest/apireference/API_UpdateDomainConfiguration.html)*中的[CreateDomainConfiguration](https://docs.aws.amazon.com//iot/latest/apireference/API_CreateDomainConfiguration.html)和。有关域配置的更多信息，请参阅[域配置](https://docs.aws.amazon.com//iot/latest/developerguide/iot-custom-endpoints-configurable.html)。

# 使用自定义身份验证 AWS IoT Core 进行连接
<a name="custom-auth"></a>

 设备可以通过自定义身份验证与任何 AWS IoT Core 支持设备消息传递的协议进行连接。 AWS IoT Core 有关受支持的通信协议的更多信息，请参阅 [设备通信协议](protocols.md)。  您传递给授权方 Lambda 函数的连接数据取决于您使用的协议。有关创建授权方 Lambda 函数的更多信息，请参阅 [定义您的 Lambda 函数](custom-auth-lambda.md)。以下部分说明如何使用每个支持的协议连接到身份验证。

## HTTPS
<a name="custom-auth-http"></a>

使用 [HTTP 发布 API 向 AWS IoT Core 其发送数据的设备可以在其 HTTP P](https://docs.aws.amazon.com/iot/latest/apireference/API_iotdata_Publish.html) OST 请求中通过请求标头或查询参数传递凭证。设备可以使用 `x-amz-customauthorizer-name` 标头或查询参数指定要调用的授权方。如果您在授权方中启用了令牌签名，则必须使用请求标头或查询参数传递 `token-key-name` 和 `x-amz-customauthorizer-signature`。请注意，在`token-signature`浏览器中使用 JavaScript 该值时必须经过网址编码。

**注意**  
HTTPS 协议的客户授权方仅支持发布操作。有关 HTTPS 协议的更多信息，请参阅[设备通信协议](protocols.md)。

以下示例请求显示了如何使用请求标头和查询参数传递这些参数。

```
//Passing credentials via headers
POST /topics/topic?qos=qos HTTP/1.1
Host: your-endpoint 
x-amz-customauthorizer-signature: token-signature
token-key-name: token-value 
x-amz-customauthorizer-name: authorizer-name

//Passing credentials via query parameters
POST /topics/topic?qos=qos&x-amz-customauthorizer-signature=token-signature&token-key-name=token-value HTTP/1.1
```

## MQTT
<a name="custom-auth-mqtt"></a>

 使用 MQTT 连接连接的设备可以通过 MQTT 消息的`username`和`password`字段传递凭证。 AWS IoT Core `username` 值也可以选择将其他值（包括令牌、签名和授权方名称）传递给授权方的查询字符串包含在内。如果要使用基于令牌的身份验证方案而不是 `username` 和 `password` 值，则可以使用此查询字符串。  

**注意**  
 密码字段中的数据由 base64 编码。 AWS IoT Core您的 Lambda 函数必须对其进行解码。

 以下示例包含一个 `username` 字符串，其中带有指定令牌和签名的额外参数。  

```
username?x-amz-customauthorizer-name=authorizer-name&x-amz-customauthorizer-signature=token-signature&token-key-name=token-value
```

要调用授权方，使用 MQTT 和自定义身份验证连接的设备必须 AWS IoT Core 通过端口 443 进行连接。它们还必须通过应用层协议协商 (ALPN) TLS 扩展（值为）`mqtt`和服务器名称指示 (SNI) 扩展名及其 AWS IoT Core 数据端点的主机名。为避免潜在的错误，`x-amz-customauthorizer-signature` 的值应采用 URL 编码。我们还强烈建议 `x-amz-customauthorizer-name` 和 `token-key-name` 的值采用 URL 编码。有关这些值的更多信息，请参阅 [设备通信协议](protocols.md)。V2 [AWS IoT Device SDK、Mobile SDK 和 AWS IoT Device Client](iot-sdks.md) 可以配置这两个扩展。 

## MQTT 结束了 WebSockets
<a name="custom-auth-websockets"></a>

 使用 MQTT 连接的设备 WebSockets 可以通过以下两种方式之一传递证书。 AWS IoT Core 
+ 通过 HTTP UPGRADE 请求中的请求标头或查询参数来建立 WebSockets 连接。
+ 通过 `username` 和 `password` 字段中的 MQTT CONNECT 消息。

 如果您通过 MQTT 连接消息传递凭证，则需要使用 ALPN 和 SNI TLS 扩展。有关这些扩展的更多信息，请参阅 [MQTT](#custom-auth-mqtt)。以下示例演示如何通过 HTTP Upgrade 请求传递凭证。

```
GET /mqtt HTTP/1.1
Host: your-endpoint 
Upgrade: WebSocket 
Connection: Upgrade 
x-amz-customauthorizer-signature: token-signature
token-key-name: token-value 
sec-WebSocket-Key: any random base64 value 
sec-websocket-protocol: mqtt 
sec-WebSocket-Version: websocket version
```

## 签名令牌
<a name="custom-auth-token-signature"></a>

必须使用 `create-authorizer` 调用中用到的公私密钥对的私有秘钥签署令牌。以下示例说明如何使用类似 Unix 的命令创建令牌签名和。 JavaScript它们使用 SHA-256 哈希算法对签名进行编码。

------
#### [ Command line ]

```
echo -n TOKEN_VALUE | openssl dgst -sha256 -sign PEM encoded RSA private key | openssl base64
```

------
#### [ JavaScript ]

```
const crypto = require('crypto')

const key = "PEM encoded RSA private key"

const k = crypto.createPrivateKey(key)
let sign = crypto.createSign('SHA256')
sign.write(t)
sign.end()
const s = sign.sign(k, 'base64')
```

------

# 授权方故障排除
<a name="custom-auth-troubleshooting"></a>

 本主题介绍可能导致自定义身份验证工作流中出现故障的常见问题以及解决这些问题的步骤。要最有效地解决问题，请启用 CloudWatch 日志 AWS IoT Core 并将日志级别设置为 **DEBUG**。您可以在 AWS IoT Core 控制台中启用 CloudWatch 日志（[https://console.aws.amazon.com/iot/](https://console.aws.amazon.com/iot/)）。有关启用和配置适用于 AWS IoT Core的日志的更多信息，请参阅 [配置 AWS IoT 日志](configure-logging.md)。

**注意**  
如果您将日志级别长时间保持在 **DEBUG**，则 CloudWatch 可能会存储大量的日志数据。这可能会增加您的 CloudWatch 费用。考虑使用基于资源的日志记录来增加仅针对特定事物组中设备的详细程度。有关基于资源的日志记录的更多信息，请参阅 [配置 AWS IoT 日志](configure-logging.md)。此外，当您完成故障排除时，将日志级别降到详细程度较低的级别。

在您开始故障排除之前，请查看 [了解自定义身份验证工作流](custom-authorizer.md) 获取自定义身份验证过程的高度概要视图。这有助于您了解应该在何处查找问题的根源。

本主题将讨论以下两个方面供您调查。
+ 与授权方 Lambda 函数相关的问题。
+ 与您的设备相关的问题。

## 检查授权方的 Lambda 函数中是否存在问题
<a name="custom-auth-troubleshooting-lambda"></a>

执行以下步骤以确保设备的连接尝试正在调用 Lambda 函数。

1. 验证哪个 Lambda 函数与您的授权方相关联。

   您可以通过调用 [DescribeAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_DescribeAuthorizer.html)API 或在 AWS IoT Core 控制台的 “**安全**” 部分中单击所需的授权者来执行此操作。

1. 检查 Lambda 函数的调用指标。为此，请执行以下步骤。

   1. 打开 AWS Lambda 控制台 ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/))，然后选择与您的授权方关联的功能。

   1. 选择**监控**选项卡并查看与您的问题相关的时间范围的指标。

1. 如果您没有看到任何调用，请验证是否 AWS IoT Core 有权调用您的 Lambda 函数。如果您看到调用，则跳到下一步。执行以下步骤以验证 Lambda 函数是否具有所需的权限。

   1. 在 AWS Lambda 控制台中为您的函数选择 “**权限**” 选项卡。

   1. 在页面底部找到**基于资源的策略**部分。如果您的 Lambda 函数具有所需的权限，则策略类似于以下示例。  
****  

      ```
      {
        "Version":"2012-10-17",		 	 	 
        "Id": "default",
        "Statement": [
          {
            "Sid": "Id123",
            "Effect": "Allow",
            "Principal": {
              "Service": "iot.amazonaws.com"
            },
            "Action": "lambda:InvokeFunction",
            "Resource": "arn:aws:lambda:us-east-1:111111111111:function:FunctionName",
            "Condition": {
              "ArnLike": {
                "AWS:SourceArn": "arn:aws:iot:us-east-1:111111111111:authorizer/AuthorizerName"
              },
              "StringEquals": {
                "AWS:SourceAccount": "111111111111"
              }
            }
          }
        ]
      }
      ```

   1. 此政策将您的职能`InvokeFunction`权限授予 AWS IoT Core 委托人。如果您没有看到它，则必须使用 [AddPermission](https://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html)API 进行添加。以下示例说明如何使用 AWS CLI执行此操作。

      ```
      aws lambda add-permission --function-name FunctionName --principal iot.amazonaws.com --source-arn AuthorizerARn --statement-id Id-123 --action "lambda:InvokeFunction"
      ```

1. 如果您看到调用，请验证没有错误。错误可能表明 Lambda 函数未正确处理 AWS IoT Core 发送给它的连接事件。

   有关在 Lambda 函数中处理事件的信息，请参阅 [定义您的 Lambda 函数](custom-auth-lambda.md)。您可以使用 AWS Lambda 控制台 ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)) 中的测试功能对函数中的测试值进行硬编码，以确保该函数正确处理事件。

1. 如果您看到没有错误的调用，但您的设备无法连接（或发布、订阅和接收消息），则问题可能是 Lambda 函数返回的策略未授予设备尝试执行的操作的权限。执行以下步骤以确定函数返回的策略是否存在任何问题。

   1. 使用 Amazon CloudWatch Logs Insights 查询在短时间内扫描日志，以检查是否存在故障。以下示例查询按时间戳对事件进行排序并查找失败。

      ```
      display clientId, eventType, status, @timestamp | sort @timestamp desc | filter status = "Failure"    
      ```

   1. 更新您的 Lambda 函数以记录它返回的数据 AWS IoT Core 以及触发该函数的事件。您可以使用这些日志检查函数创建的策略。

1. 如果您看到调用并没有错误，但您的设备无法连接（或发布、订阅和接收消息），则另一个原因可能是 Lambda 函数超出了超时限制。自定义授权方的 Lambda 函数超时限制为 5 秒。您可以在 CloudWatch 日志或指标中查看函数持续时间。

## 调查设备问题
<a name="custom-auth-troubleshooting-investigate"></a>

如果您发现调用 Lambda 函数或函数返回的策略不存在任何问题，请查找设备连接尝试是否存在问题。格式错误的连接请求可能导致 AWS IoT Core 无法触发您的授权者。TLS 层和应用程序层均可能出现连接问题。

**TLS 层可能存在的问题：**
+ 客户必须在所有自定义身份验证请求中传递主机名标头（HTTP、MQTT WebSockets）或服务器名称指示 TLS 扩展（HTTP、MQTT over WebSockets、MQTT）。在这两种情况下，传递的值都必须与您账户 AWS IoT Core 的数据端点之一匹配。这些是执行以下 CLI 命令时返回的端点。
  + `aws iot describe-endpoint --endpoint-type iot:Data-ATS`
  + `aws iot describe-endpoint --endpoint-type iot:Data`（适用于旧版 VeriSign 终端节点）
+ 在 MQTT 连接中使用自定义身份验证的设备还必须发送应用程序层协议协商（ALPN）TLS 扩展，并具有值 `mqtt`。
+ 自定义身份验证当前仅在端口 443 上可用。

**应用层可能存在的问题：**
+ 如果启用了签名（`signingDisabled` 字段在您的授权方为 false），请查找以下签名问题。
  + 请确保使用 `x-amz-customauthorizer-signature` 标头或查询字符串参数传递令牌签名。
  + 确保服务没有签署令牌以外的值。
  + 请确保使用您在授权方的 `token-key-name` 字段中指定的标头或查询参数中传递令牌。
+ 请确保您使用 `x-amz-customauthorizer-name` 标头或查询字符串参数传递的授权方名称是有效的，或者您已为您的账户定义了默认授权方。