

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

# 自定义身份验证质询 Lambda 触发器
<a name="user-pool-lambda-challenge"></a>

在为 Amazon Cognito 用户池构建身份验证流程时，您可能会发现需要在内置流程的基础上对身份验证模型进行扩展。自定义质询触发器的一个常见使用场景是在用户名、密码和多重身份验证（MFA）之外实施额外的安全检查。自定义质询是您可以使用 Lambda 支持的编程语言生成的任何问题和回答。例如，在允许用户进行身份验证之前，您可能希望要求用户先破解验证码或回答安全问题。另一个潜在的需求是与专门的身份验证因素或设备集成。或者，您可能已经开发了使用硬件安全密钥或生物识别设备对用户进行身份验证的软件。自定义质询的身份验证成功的定义是，您的 Lambda 函数接受为正确的答案：例如，固定字符串或来自外部 API 的满意响应。

您可以使用自定义质询开始身份验证并完全控制身份验证过程，也可以在应用程序收到自定义质询之前执行用户名和密码身份验证。

自定义身份验证质询 Lambda 触发器：

**[定义](user-pool-lambda-define-auth-challenge.md)**  
启动质询序列。确定您是要启动新的质询、将身份验证标记为已完成，还是要停止身份验证尝试。

**[创建](user-pool-lambda-create-auth-challenge.md)**  
向您的应用程序发出用户必须回答的问题。此函数可能会呈现安全问题或指向验证码的链接，您的应用程序应将其显示给用户。

**[验证](user-pool-lambda-verify-auth-challenge-response.md)**  
知道预期答案并将其与您的应用程序在质询响应中提供的答案进行比较。该函数可能会调用您的验证码服务的 API 来检索用户尝试的解决方案的预期结果。

这三个 Lambda 函数链接在一起，呈现出一种完全由您控制且由您自己设计的身份验证机制。由于自定义身份验证需要在您的客户端和 Lambda 函数中使用应用程序逻辑，因此您无法在托管登录中处理自定义身份验证。此身份验证系统需要开发人员付出额外的努力。您的应用程序必须使用用户池 API 执行身份验证流程，并使用定制登录界面处理由此产生的质询，该界面可在自定义身份验证质询的中心呈现问题。

![\[质询 Lambda 触发器\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/images/lambda-challenges.png)


有关实施自定义身份验证的更多信息，请参阅[自定义身份验证流程和质询](amazon-cognito-user-pools-authentication-flow-methods.md#Custom-authentication-flow-and-challenges)。

API 操作之间的身份验证[InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html)或[AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html)、和[RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html)或[AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html)。在此流程中，用户通过回答连续的质询进行身份验证，直到身份验证失败或用户获得令牌。质询回应可能是一个新的挑战。在这种情况下，您的应用程序会根据需要多次响应新的质询。当定义身份验证质询函数分析到目前为止的结果时，确定所有质询都已回答并返回 `IssueTokens` 时，身份验证就会成功。

**Topics**
+ [自定义质询流程中的 SRP 身份验证](#user-pool-lambda-challenge-srp-authentication)
+ [定义身份验证质询 Lambda 触发器](user-pool-lambda-define-auth-challenge.md)
+ [创建身份验证质询 Lambda 触发器](user-pool-lambda-create-auth-challenge.md)
+ [验证身份验证质询响应 Lambda 触发器](user-pool-lambda-verify-auth-challenge-response.md)

## 自定义质询流程中的 SRP 身份验证
<a name="user-pool-lambda-challenge-srp-authentication"></a>

您可以让 Amazon Cognito 在发出自定义质询之前验证用户密码。当您在自定义质询流程中执行 SRP 身份验证时，[请求频率限额](quotas.md#category_operations.title)身份验证类别中关联的任何 Lambda 触发器都将运行。过程概述如下：

1. 您的应用程序使用 `AuthParameters` 映射来调用 `InitiateAuth` 或 `AdminInitiateAuth`，以此来启动登录。参数必须包括 `CHALLENGE_NAME: SRP_A,` 以及 `SRP_A` 和 `USERNAME` 的值。

1. Amazon Cognito 使用包含 `challengeName: SRP_A` 和 `challengeResult: true` 的初始会话，调用您定义的身份验证质询 Lambda 触发器。

1. 在收到这些输入后，您的 Lambda 函数发出 `challengeName: PASSWORD_VERIFIER`、`issueTokens: false`、`failAuthentication: false` 响应。

1. 如果密码验证成功，Amazon Cognito 会使用包含 `challengeName: PASSWORD_VERIFIER` 和 `challengeResult: true` 的新会话再次调用您的 Lambda 函数。

1. 为了启动您的自定义质询，Lambda 函数发出 `challengeName: CUSTOM_CHALLENGE`、`issueTokens: false` 和 `failAuthentication: false` 响应。如果您不想启动包含密码验证的自定义身份验证流程，可以使用 `AuthParameters` 映射（包括 `CHALLENGE_NAME: CUSTOM_CHALLENGE`）启动登录。

1. 质询循环将一直重复到所有质询得到应答。

以下在使用 SRP 流进行自定义身份验证之前的起始 `InitiateAuth` 请求的示例。

```
{
    "AuthFlow": "CUSTOM_AUTH",
    "ClientId": "1example23456789",
    "AuthParameters": {
        "CHALLENGE_NAME": "SRP_A",
        "USERNAME": "testuser",
        "SRP_A": "[SRP_A]",
        "SECRET_HASH": "[secret hash]"
    }
}
```

### 在自定义身份验证 SRP 流程中重置密码
<a name="user-pool-lambda-challenge-force-password-change"></a>

当用户处于 `FORCE_CHANGE_PASSWORD` 状态时，您的自定义身份验证流程必须集成密码更改步骤，同时保持身份验证质询的完整性。Amazon Cognito 会在 `NEW_PASSWORD_REQUIRED` 质询期间调用您的[定义身份验证质询](user-pool-lambda-define-auth-challenge.md) Lambda 触发器。在这种情况下，使用自定义质询流程和 SRP 身份验证登录的用户如果处于密码重置状态，则可以设置新密码。

当用户处于 `RESET_REQUIRED` 或 `FORCE_CHANGE_PASSWORD` 状态时，他们必须使用 `NEW_PASSWORD` 来[回应](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html#API_RespondToAuthChallenge_RequestParameters) `NEW_PASSWORD_REQUIRED` 质询。在使用 SRP 的自定义身份验证中，Amazon Cognito 会在用户完成 SRP `PASSWORD_VERIFIER` 质询后返回一个 `NEW_PASSWORD_REQUIRED` 质询。您的“定义身份验证质询”触发器会收到 `session` 数组中的两个质询结果，并可在用户成功更改密码后继续执行额外的自定义质询。

您的“定义身份验证质询”Lambda 触发器必须通过 SRP 身份验证、密码重置和随后的自定义质询来管理质询序列。该触发器会在 `session` 参数中收到一个已完成质询的数组，其中包括 `PASSWORD_VERIFIER` 和 `NEW_PASSWORD_REQUIRED` 的结果。如需了解实现示例，请参阅[定义身份验证质询示例](user-pool-lambda-define-auth-challenge.md#aws-lambda-triggers-define-auth-challenge-example)。

#### 身份验证流程步骤
<a name="user-pool-lambda-challenge-password-flow-steps"></a>

对于需要在自定义质询之前验证密码的用户，该过程遵循以下步骤：

1. 您的应用程序使用 `AuthParameters` 映射来调用 `InitiateAuth` 或 `AdminInitiateAuth`，以此来启动登录。参数必须包括 `CHALLENGE_NAME: SRP_A`，以及 `SRP_A` 和 `USERNAME` 的值。

1. Amazon Cognito 使用包含 `challengeName: SRP_A` 和 `challengeResult: true` 的初始会话，调用您定义的身份验证质询 Lambda 触发器。

1. 在收到这些输入后，您的 Lambda 函数发出 `challengeName: PASSWORD_VERIFIER`、`issueTokens: false`、`failAuthentication: false` 响应。

1. 如果密码验证成功，则会发生以下两种情况之一：  
**对于处于正常状态的用户：**  
Amazon Cognito 会使用包含 `challengeName: PASSWORD_VERIFIER` 和 `challengeResult: true` 的新会话再次调用您的 Lambda 函数。  
为了启动您的自定义质询，Lambda 函数发出 `challengeName: CUSTOM_CHALLENGE`、`issueTokens: false` 和 `failAuthentication: false` 响应。  
**对于处于 `RESET_REQUIRED` 或 `FORCE_CHANGE_PASSWORD` 状态的用户：**  
Amazon Cognito 会使用包含 `challengeName: PASSWORD_VERIFIER` 和 `challengeResult: true` 的会话调用您的 Lambda 函数。  
您的 Lambda 函数应该使用 `challengeName: NEW_PASSWORD_REQUIRED`、`issueTokens: false` 和 `failAuthentication: false` 作出响应。  
成功更改密码后，Amazon Cognito 会使用包含 `PASSWORD_VERIFIER` 和 `NEW_PASSWORD_REQUIRED` 的会话调用您的 Lambda 函数。  
为了启动您的自定义质询，Lambda 函数发出 `challengeName: CUSTOM_CHALLENGE`、`issueTokens: false` 和 `failAuthentication: false` 响应。

1. 质询循环将一直重复到所有质询得到应答。

如果您不想启动包含密码验证的自定义身份验证流程，可以使用 `AuthParameters` 映射（包括 `CHALLENGE_NAME: CUSTOM_CHALLENGE`）启动登录。

#### 会话管理
<a name="user-pool-lambda-challenge-session-management"></a>

身份验证流程通过一系列会话 IDs 和质询结果来保持会话的连续性。每个质询响应都会生成一个新的会话 ID，以防止会话重用错误，这对于多重身份验证流程尤其重要。

质询结果按时间顺序存储在您的 Lambda 触发器接收的会话数组中。对于处于 `FORCE_CHANGE_PASSWORD` 状态的用户，该会话数组包含：

1. `session[0]` - 最初的 `SRP_A` 质询

1. `session[1]` - `PASSWORD_VERIFIER` 的结果

1. `session[2]` - `NEW_PASSWORD_REQUIRED` 的结果

1. 后续要素 - 其他自定义质询的结果

#### 身份验证流程示例
<a name="user-pool-lambda-challenge-example-flow"></a>

以下示例展示了一个完整的自定义身份验证流程，在该流程中，一个处于 `FORCE_CHANGE_PASSWORD` 状态的用户必须完成密码更改和自定义 CAPTCHA 质询。

1. **InitiateAuth request**

   ```
   {
       "AuthFlow": "CUSTOM_AUTH",
       "ClientId": "1example23456789",
       "AuthParameters": {
           "CHALLENGE_NAME": "SRP_A",
           "USERNAME": "testuser",
           "SRP_A": "[SRP_A]"
       }
   }
   ```

1. **InitiateAuth 响应**

   ```
   {
       "ChallengeName": "PASSWORD_VERIFIER",
       "ChallengeParameters": {
           "USER_ID_FOR_SRP": "testuser"
       },
       "Session": "[session_id_1]"
   }
   ```

1. **RespondToAuthChallenge 请求用 `PASSWORD_VERIFIER`**

   ```
   {
       "ChallengeName": "PASSWORD_VERIFIER",
       "ClientId": "1example23456789",
       "ChallengeResponses": {
           "PASSWORD_CLAIM_SIGNATURE": "[claim_signature]",
           "PASSWORD_CLAIM_SECRET_BLOCK": "[secret_block]",
           "TIMESTAMP": "[timestamp]",
           "USERNAME": "testuser"
       },
       "Session": "[session_id_1]"
   }
   ```

1. **RespondToAuthChallenge 用`NEW_PASSWORD_REQUIRED`挑战回应**

   ```
   {
       "ChallengeName": "NEW_PASSWORD_REQUIRED",
       "ChallengeParameters": {},
       "Session": "[session_id_2]"
   }
   ```

1. **RespondToAuthChallenge 请求用 `NEW_PASSWORD_REQUIRED`**

   ```
   {
       "ChallengeName": "NEW_PASSWORD_REQUIRED",
       "ClientId": "1example23456789",
       "ChallengeResponses": {
           "NEW_PASSWORD": "[password]",
           "USERNAME": "testuser"
       },
       "Session": "[session_id_2]"
   }
   ```

1. **RespondToAuthChallenge 使用 CAPTCHA 自定义挑战进行回应**

   ```
   {
       "ChallengeName": "CUSTOM_CHALLENGE",
       "ChallengeParameters": {
           "captchaUrl": "url/123.jpg"
       },
       "Session": "[session_id_3]"
   }
   ```

1. **RespondToAuthChallenge 请求并附上 CAPTCHA 自定义质询的答案**

   ```
   {
       "ChallengeName": "CUSTOM_CHALLENGE",
       "ClientId": "1example23456789",
       "ChallengeResponses": {
           "ANSWER": "123",
           "USERNAME": "testuser"
       },
       "Session": "[session_id_3]"
   }
   ```

**6。最终成功响应**

```
{
    "AuthenticationResult": {
        "AccessToken": "eyJra456defEXAMPLE",
        "ExpiresIn": 3600,
        "IdToken": "eyJra789ghiEXAMPLE",
        "RefreshToken": "eyJjd123abcEXAMPLE",
        "TokenType": "Bearer"
    },
    "ChallengeParameters": {}
}
```

# 定义身份验证质询 Lambda 触发器
<a name="user-pool-lambda-define-auth-challenge"></a>

定义身份验证质询触发器是一个 Lambda 函数，用于在自定义身份验证流程中维护质询序列。它声明质询序列的成功或失败，并在序列尚未完成时设置下一个质询。

![\[质询 Lambda 触发器\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/images/lambda-challenges1.png)


**定义身份验证质询**  
 Amazon Cognito 调用此触发器以启动[自定义身份验证流程](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow)。

此 Lambda 触发器的请求包括 `session`。`session` 参数是一个数组，包含在当前身份验证流程中向用户显示的所有质询。请求还包含相应的结果。`session` 数组按照时间顺序存储质询详细信息 (`ChallengeResult`)。质询 `session[0]` 表示用户收到的第一个质询。

**Topics**
+ [定义身份验证质询 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-define-auth-challenge)
+ [定义身份验证质询示例](#aws-lambda-triggers-define-auth-challenge-example)

## 定义身份验证质询 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-define-auth-challenge"></a>

Amazon Cognito 传递给此 Lambda 函数的请求是以下参数和 Amazon Cognito 添加到所有请求中的[常用参数](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared)的组合。

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "string": "string",
                . . .
        },
        "session": [
            ChallengeResult,
            . . .
        ],
        "clientMetadata": {
            "string": "string",
            . . .
        },
        "userNotFound": boolean
    },
    "response": {
        "challengeName": "string",
        "issueTokens": boolean,
        "failAuthentication": boolean
    }
}
```

------

### 定义身份验证质询请求参数
<a name="cognito-user-pools-lambda-trigger-syntax-define-auth-challenge-request"></a>

 当 Amazon Cognito 调用您的 Lambda 函数时，Amazon Cognito 提供以下参数：

**userAttributes**  
表示用户属性的一个或多个名称/值对。

**userNotFound**  
一个布尔值，当您的用户池客户端将 `PreventUserExistenceErrors` 设置为 `ENABLED` 时，Amazon Cognito 将填充该值。值 `true` 表示用户 ID（用户名、电子邮件地址以及其他详细信息）不匹配任何现有用户。当 `PreventUserExistenceErrors` 设置为 `ENABLED` 时，该服务不会向应用程序通知不存在的用户。建议您的 Lambda 函数保持相同的用户体验并考虑延迟。这样，不论用户是否存在，调用方都不会检测到不同的行为。

**会话**  
`ChallengeResult` 元素的数组。每个数组包含以下元素：    
**challengeName**  
以下质询类型之一：`CUSTOM_CHALLENGE`、`SRP_A`、`PASSWORD_VERIFIER`、`SMS_MFA`、`EMAIL_OTP`、`SOFTWARE_TOKEN_MFA`、`DEVICE_SRP_AUTH`、`DEVICE_PASSWORD_VERIFIER` 或 `ADMIN_NO_SRP_AUTH`。  
当您的定义身份验证质询功能向已设置多重身份验证的用户发出 `PASSWORD_VERIFIER` 质询时，Amazon Cognito 会随后提出 `SMS_MFA`、`EMAIL_OTP` 或 `SOFTWARE_TOKEN_MFA` 质询。这些是多重身份验证代码的提示。在您的函数中，包括对来自 `SMS_MFA`、`EMAIL_OTP` 和 `SOFTWARE_TOKEN_MFA` 质询的输入事件的处理。您无需在定义身份验证质询函数中调用任何 MFA 质询。  
在函数确定用户是否已成功通过身份验证以及是否应向其颁发令牌时，请始终检查定义身份验证质询函数中的 `challengeName` 以及它是否与预期值匹配。  
**challengeResult**  
如果用户成功完成质询，则设置为 `true`，否则设置为 `false`。  
**challengeMetadata**  
您的自定义质询的名称。仅当 `challengeName` 为 `CUSTOM_CHALLENGE` 时使用。

**clientMetadata**  
一个或多个键值对，您可以将其作为自定义输入内容提供给为定义身份验证质询触发器指定的 Lambda 函数。要将此数据传递给您的 Lambda 函数，您可以在[AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html)和 [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html)API 操作中使用`ClientMetadata`参数。调用 define auth 质询函数的请求不包括在 API 操作中的 ClientMetadata 参数中[AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html)传递的数据。[InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html)

### 定义身份验证质询响应参数
<a name="cognito-user-pools-lambda-trigger-syntax-define-auth-challenge-response"></a>

在响应中，您可以返回身份验证流程的下一阶段。

**challengeName**  
一个字符串，其中包含下一质询的名称。如果您希望向您的用户显示新的质询，请在此处指定质询名称。

**issueTokens**  
如果您确定用户已充分完成了身份验证质询，则设置为 `true`。如果用户没有充分满足质询条件，则设置为 `false`。

**failAuthentication**  
如果您想要终止当前的身份验证流程，则设置为 `true`。要继续当前的身份验证流程，请设置为 `false`。

## 定义身份验证质询示例
<a name="aws-lambda-triggers-define-auth-challenge-example"></a>

此示例针对身份验证定义一系列质询，并仅在用户成功完成所有质询后发布令牌。当用户使用 `SRP_A` 和 `PASSWORD_VERIFIER` 质询完成 SRP 身份验证时，此功能会向他们传递一个 `CUSTOM_CHALLENGE`，用于调用“创建身份验证质询”触发器。结合我们的[创建身份验证质询示例](user-pool-lambda-create-auth-challenge.md#aws-lambda-triggers-create-auth-challenge-example)，此序列为质询三提供了 CAPTCHA 质询，为质询四提供了安全问题。

用户完成 CAPTCHA 并回答安全问题后，此功能将确认您的用户池可以颁发令牌。不需要进行 SRP 身份验证；您也可以将 CAPTCHA 和安全问题设置为质询一和二。如果您的“定义身份验证质询”功能未声明 SRP 质询，则用户的成功完全取决于他们对您的自定义提示的响应。

------
#### [ Node.js ]

```
const handler = async (event) => {
  if (
    event.request.session.length === 1 &&
    event.request.session[0].challengeName === "SRP_A"
  ) {
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "PASSWORD_VERIFIER";
  } else if (
    event.request.session.length === 2 &&
    event.request.session[1].challengeName === "PASSWORD_VERIFIER" &&
    event.request.session[1].challengeResult === true
  ) {
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "CUSTOM_CHALLENGE";
  } else if (
    event.request.session.length === 3 &&
    event.request.session[2].challengeName === "CUSTOM_CHALLENGE" &&
    event.request.session[2].challengeResult === true
  ) {
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "CUSTOM_CHALLENGE";
  } else if (
    event.request.session.length === 4 &&
    event.request.session[3].challengeName === "CUSTOM_CHALLENGE" &&
    event.request.session[3].challengeResult === true
  ) {
    event.response.issueTokens = true;
    event.response.failAuthentication = false;
  } else {
    event.response.issueTokens = false;
    event.response.failAuthentication = true;
  }

  return event;
};

export { handler };
```

------

# 创建身份验证质询 Lambda 触发器
<a name="user-pool-lambda-create-auth-challenge"></a>

创建身份验证质询触发器是一个 Lambda 函数，其中包含由定义身份验证质询触发器声明的每个质询的详细信息。它处理由定义身份验证质询触发器声明的质询名称，并返回 `publicChallengeParameters`，您的应用程序必须将其呈现给用户。然后，此函数为您的用户池提供质询 `privateChallengeParameters` 的答案，您的用户池会将该质询传递给验证身份验证质询触发器。在您的定义身份验证质询触发器管理质询序列的地方，您的创建身份验证质询触发器管理质询内容。

![\[质询 Lambda 触发器\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/images/lambda-challenges2.png)


**创建身份验证质询**  
如果指定自定义质询作为**定义身份验证质询** 触发器的一部分，则 Amazon Cognito 会在**定义身份验证质询**之后调用此触发器。它将创建一个[自定义身份验证流程](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow)。

系统调用此 Lambda 触发器来创建要向用户显示的质询。此 Lambda 触发器的请求包括 `challengeName` 和 `session`。`challengeName` 是一个字符串，是向用户显示的下一质询的名称。此属性的值在定义身份验证质询 Lambda 触发器中设置。

质询循环将一直重复到所有质询得到应答。

**Topics**
+ [创建身份验证质询 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-create-auth-challenge)
+ [创建身份验证质询示例](#aws-lambda-triggers-create-auth-challenge-example)

## 创建身份验证质询 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-create-auth-challenge"></a>

Amazon Cognito 传递给此 Lambda 函数的请求是以下参数和 Amazon Cognito 添加到所有请求中的[常用参数](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared)的组合。

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "string": "string",
            . . .
        },
        "challengeName": "string",
        "session": [
            ChallengeResult,
            . . .
        ],
        "clientMetadata": {
            "string": "string",
            . . .
        },
        "userNotFound": boolean
    },
    "response": {
        "publicChallengeParameters": {
            "string": "string",
            . . .
        },
        "privateChallengeParameters": {
            "string": "string",
            . . .
        },
        "challengeMetadata": "string"
    }
}
```

------

### 创建身份验证质询请求参数
<a name="cognito-user-pools-lambda-trigger-syntax-create-auth-challenge-request"></a>

**userAttributes**  
表示用户属性的一个或多个名称/值对。

**userNotFound**  
当为您的用户池客户端将 `PreventUserExistenceErrors` 设置为 `ENABLED` 时，将填充此布尔值。

**challengeName**  
新质询的名称。

**会话**  
会话元素是一组 `ChallengeResult` 元素，其中，每个元素包含以下元素：    
**challengeName**  
质询类型。以下值之一：`"CUSTOM_CHALLENGE"`、`"PASSWORD_VERIFIER"`、`"SMS_MFA"`、`"DEVICE_SRP_AUTH"`、`"DEVICE_PASSWORD_VERIFIER"`、`"NEW_PASSWORD_REQUIRED"` 或 `"ADMIN_NO_SRP_AUTH"`。  
**challengeResult**  
如果用户成功完成质询，则设置为 `true`，否则设置为 `false`。  
**challengeMetadata**  
您的自定义质询的名称。仅当 `challengeName` 为 `"CUSTOM_CHALLENGE"` 时使用。

**clientMetadata**  
一个或多个键值对，您可以将其作为自定义输入内容提供给为创建身份验证质询触发器指定的 Lambda 函数。您可以使用[AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html)和 [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html)API 操作中的 ClientMetadata 参数将此数据传递给您的 Lambda 函数。调用 create auth 质询函数的请求不包括在 API 操作中的 ClientMetadata [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html)参数中传递的数据。[InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html)

### 创建身份验证质询响应参数
<a name="cognito-user-pools-lambda-trigger-syntax-create-auth-challenge-response"></a>

**publicChallengeParameters**  
客户端应用程序要在向用户显示的质询中使用的一个或多个键/值对。此参数应包含所有必要信息，以向用户准确显示质询。

**privateChallengeParameters**  
此参数仅由验证身份验证质询响应 Lambda 触发器使用。此参数应包含所需的所有信息，以验证用户对质询的响应。也就是说，`publicChallengeParameters` 参数包含向用户显示的问题，`privateChallengeParameters` 包含问题的有效答案。

**challengeMetadata**  
您的自定义质询的名称（如果是自定义质询）。

## 创建身份验证质询示例
<a name="aws-lambda-triggers-create-auth-challenge-example"></a>

此功能包含两个自定义质询，对应于我们[定义身份验证质询示例](user-pool-lambda-define-auth-challenge.md#aws-lambda-triggers-define-auth-challenge-example)中的质询序列。前两个质询为 SRP 身份验证。在第三个质询中，此功能会在质询响应中向您的应用程序返回一个 CAPTCHA URL。您的应用程序根据该 URL 呈现 CAPTCHA，并返回用户的输入。CAPTCHA 图像的 URL 作为 `captchaUrl` 添加到公有质询参数中，并且预期答案添加到私有质询参数中。

在第四个质询中，此功能会返回一个安全问题。您的应用程序会呈现该问题并提示用户输入答案。当用户完成这两个自定义质询后，“定义身份验证质询”触发器将确认用户池可以颁发令牌。

------
#### [ Node.js ]

```
const handler = async (event) => {
  if (event.request.challengeName !== "CUSTOM_CHALLENGE") {
    return event;
  }

  if (event.request.session.length === 2) {
    event.response.publicChallengeParameters = {};
    event.response.privateChallengeParameters = {};
    event.response.publicChallengeParameters.captchaUrl = "url/123.jpg";
    event.response.privateChallengeParameters.answer = "5";
  }

  if (event.request.session.length === 3) {
    event.response.publicChallengeParameters = {};
    event.response.privateChallengeParameters = {};
    event.response.publicChallengeParameters.securityQuestion =
      "Who is your favorite team mascot?";
    event.response.privateChallengeParameters.answer = "Peccy";
  }

  return event;
};

export { handler };
```

------

# 验证身份验证质询响应 Lambda 触发器
<a name="user-pool-lambda-verify-auth-challenge-response"></a>

验证身份验证质询触发器是一个 Lambda 函数，用于将用户提供的响应与已知回答进行比较。此功能告诉您的用户池，用户是否正确回答了质询。当验证身份验证质询触发器对 `answerCorrect` 的响应为 `true` 时，身份验证序列可以继续。

![\[质询 Lambda 触发器\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/images/lambda-challenges3.png)


**验证身份验证质询响应**  
Amazon Cognito 调用此触发器，以验证用户对自定义身份验证质询的响应是否有效。它是用户池[自定义身份验证流程](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow)的一部分。

此触发器的请求包括 `privateChallengeParameters` 和 `challengeAnswer` 参数。创建身份验证质询 Lambda 触发器返回 `privateChallengeParameters` 值，并包含用户的预期响应。`challengeAnswer` 参数包含用户对质询的响应。

响应包含 `answerCorrect` 属性。如果用户成功完成质询，Amazon Cognito 会将属性值设置为 `true`。如果用户未成功完成质询，Amazon Cognito 会将属性值设置为 `false`。

质询循环将一直重复，直至用户应答所有质询。

**Topics**
+ [验证身份验证质询 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-verify-auth-challenge)
+ [验证身份验证质询响应示例](#aws-lambda-triggers-verify-auth-challenge-response-example)

## 验证身份验证质询 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-verify-auth-challenge"></a>

Amazon Cognito 传递给此 Lambda 函数的请求是以下参数和 Amazon Cognito 添加到所有请求中的[常用参数](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared)的组合。

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "string": "string",
            . . .
        },
        "privateChallengeParameters": {
            "string": "string",
            . . .
        },
        "challengeAnswer": "string",
        "clientMetadata": {
            "string": "string",
            . . .
        },
        "userNotFound": boolean
    },
    "response": {
        "answerCorrect": boolean
    }
}
```

------

### 验证身份验证质询请求参数
<a name="cognito-user-pools-lambda-trigger-syntax-verify-auth-challenge-request"></a>

**userAttributes**  
此参数包含表示用户属性的一个或多个名称/值对。

**userNotFound**  
当 Amazon Cognito 将您用户池客户端的 `PreventUserExistenceErrors` 设置为 `ENABLED` 时，Amazon Cognito 将填充此布尔值。

**privateChallengeParameters**  
此参数来自创建身份验证质询触发器。为了确定用户是否通过了质询，Amazon Cognito 将参数与用户的 **challengeAnswer** 进行比较。  
此参数包含所需的所有信息，以验证用户对质询的响应。该信息包括 Amazon Cognito 向用户提出的问题 (`publicChallengeParameters`)，以及问题的有效回答 (`privateChallengeParameters`)。只有验证身份验证质询响应 Lambda 触发器使用此参数。

**challengeAnswer**  
此参数值是来自用户对质询响应的应答。

**clientMetadata**  
此参数包含一个或多个键值对，您可以将其作为自定义输入内容提供给用于验证身份验证质询触发器的 Lambda 函数。要将此数据传递给您的 Lambda 函数，请使用[AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html)和 [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html)API 操作中的 ClientMetadata 参数。Amazon Cognito 在传递给验证身份验证质询函数的请求中不包含来自 ClientMetadata 参数[AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html)和 [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html)API 操作的数据。

### 验证身份验证质询响应参数
<a name="cognito-user-pools-lambda-trigger-syntax-verify-auth-challenge-response"></a>

**answerCorrect**  
如果用户成功完成质询，Amazon Cognito 将此参数设置为 `true`。如果用户未成功完成质询，Amazon Cognito 将此参数设置为 `false`。

## 验证身份验证质询响应示例
<a name="aws-lambda-triggers-verify-auth-challenge-response-example"></a>

此“验证身份验证质询”功能用于检查用户对质询的响应是否与预期响应一致。用户的回答由您的应用程序输入来定义，正确答案则由[创建身份验证质询触发器响应](user-pool-lambda-create-auth-challenge.md#aws-lambda-triggers-create-auth-challenge-example)中的 `privateChallengeParameters.answer` 来定义。正确答案和用户回答都是此功能的输入事件的一部分。

在本例中，如果用户的响应与预期响应一致，Amazon Cognito 会将 `answerCorrect` 参数设置为 `true`。

------
#### [ Node.js ]

```
const handler = async (event) => {
  if (
    event.request.privateChallengeParameters.answer ===
    event.request.challengeAnswer
  ) {
    event.response.answerCorrect = true;
  } else {
    event.response.answerCorrect = false;
  }

  return event;
};

export { handler };
```

------