

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

# 使用 Lambda 触发器自定义用户池工作流
<a name="cognito-user-pools-working-with-lambda-triggers"></a>

Amazon Cognito 使用 AWS Lambda 函数来修改用户池的身份验证行为。您可以将您的用户池配置为在用户首次注册之前、完成身份验证之后以及两者之间的几个阶段自动调用 Lambda 函数。您的函数可以修改身份验证流程的默认行为，发出 API 请求以修改您的用户池或其他 AWS 资源，以及与外部系统通信。您的 Lambda 函数中的代码是您自己的。Amazon Cognito 会将事件数据发送到您的函数，等待函数处理数据，而且在大多数情况下，预计会出现一个响应事件，该事件反映您要对会话进行的任何更改。

在请求和响应事件系统中，您可以引入自己的身份验证挑战、在您的用户池与其他身份存储之间迁移用户、自定义消息以及修改 JSON Web 令牌（JWTs）。

Lambda 触发器可以自定义用户在您的用户池中启动操作后 Amazon Cognito 向用户提供的响应。例如，您可以阻止原本会成功的用户登录。他们还可以对您的 AWS 环境、外部环境 APIs、数据库或身份存储执行运行时操作。例如，迁移用户触发器可以将外部操作与 Amazon Cognito 中的更改相结合：您可以在外部目录中查找用户信息，然后根据该外部信息设置新用户的属性。

当您为用户池分配 Lambda 触发器时，Amazon Cognito 会中断其原定设置流程，以从您的函数请求信息。Amazon Cognito 生成 JSON *事件*并将其传递给您的函数。该事件包含有关您的用户旨在创建用户账户、登录、重置密码或更新属性的请求的信息。然后，您的函数有机会采取行动，或者将事件原封不动地发回。未经修改返回的事件会通知您的用户池继续执行对该事件的默认操作。例如，您的注册前触发器可以自动确认用户是否使用 `PreSignUp_SignUp` 触发器源，但对于外部用户和管理员创建的用户，返回的事件保持不变。

下表总结了使用 Lambda 触发器自定义用户池操作的一些方法：


****  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html)

**Topics**
+ [有关 Lambda 触发器的需知信息](#important-lambda-considerations)
+ [添加用户池 Lambda 触发器](#triggers-working-with-lambda)
+ [用户池 Lambda 触发器事件](#cognito-user-pools-lambda-trigger-event-parameter-shared)
+ [用户池 Lambda 触发器通用参数](#cognito-user-pools-lambda-trigger-syntax-shared)
+ [客户端元数据](#working-with-lambda-trigger-client-metadata)
+ [将 API 操作连接到 Lambda 触发器](#lambda-triggers-by-event)
+ [将 Lambda 触发器连接到用户池功能操作](#working-with-lambda-trigger-sources)
+ [注册前 Lambda 触发器](user-pool-lambda-pre-sign-up.md)
+ [确认后 Lambda 触发器](user-pool-lambda-post-confirmation.md)
+ [身份验证前 Lambda 触发器](user-pool-lambda-pre-authentication.md)
+ [身份验证后 Lambda 触发器](user-pool-lambda-post-authentication.md)
+ [入站联邦 Lambda 触发器](user-pool-lambda-inbound-federation.md)
+ [自定义身份验证质询 Lambda 触发器](user-pool-lambda-challenge.md)
+ [令牌生成前 Lambda 触发器](user-pool-lambda-pre-token-generation.md)
+ [迁移用户 Lambda 触发器](user-pool-lambda-migrate-user.md)
+ [自定义消息 Lambda 触发器](user-pool-lambda-custom-message.md)
+ [自定义发件人 Lambda 触发器](user-pool-lambda-custom-sender-triggers.md)

## 有关 Lambda 触发器的需知信息
<a name="important-lambda-considerations"></a>

在为 Lambda 函数准备用户池时，请考虑以下各项：
+ Amazon Cognito 发送到 Lambda 触发器的事件可能会随着新功能推出而发生变化。响应和请求元素在 JSON 层次结构中的位置可能改变，或者可能会添加元素名称。在 Lambda 函数中，您预期会收到本指南中介绍的输入元素键值对，但是更严格的输入验证可能会导致您的函数失败。
+ 您可以从 Amazon Cognito 发送到某些触发器的多个事件版本中选择一个。某些版本可能需要您接受对 Amazon Cognito 定价的更改。有关定价的更多信息，请参阅 [Amazon Cognito 定价](https://aws.amazon.com/cognito/pricing/)。要在[令牌生成前 Lambda 触发器](user-pool-lambda-pre-token-generation.md)中自定义访问令牌，您必须使用*精简版*之外的功能计划对用户池进行配置，并更新 Lambda 触发器配置以使用事件版本 2。
+ Amazon Cognito 会同步调用 Lambda 函数，但 [自定义发件人 Lambda 触发器](user-pool-lambda-custom-sender-triggers.md) 除外。Amazon Cognito 调用您的 Lambda 函数时，函数必须在 5 秒内响应。如果不是，并且可以重试呼叫，Amazon Cognito 可能会重试该呼叫。如果所有重试尝试都失败，则该函数将超时。您无法更改此 5 秒钟超时值。有关更多信息，请参阅《 AWS Lambda 开发人员指南》中的 [Lambda 编程模型](https://docs.aws.amazon.com/lambda/latest/dg/foundation-progmodel.html)。

  Amazon Cognito 不会重试返回[调用错误](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_Errors)且 HTTP 状态代码为 500-599 的函数调用。这些代码表示配置问题导致 Lambda 无法启动该函数。有关更多信息，请参阅[中的错误处理和自动重试。 AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-retries.html)
+ 您无法在 Lambda 触发器配置中声明函数版本。默认情况下，Amazon Cognito 用户池会调用您的函数的最新版本。但是，您可以将函数版本与别名相关联，并在[CreateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html)或 [UpdateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html)API 请求中`LambdaArn`将触发器设置为别名 ARN。此选项在 AWS 管理控制台中不可用。要了解有关别名的更多信息，请参阅《AWS Lambda 开发人员指南》**中的 [Lambda 函数别名](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html)。
+ 如果您删除某个 Lambda 触发器，必须更新用户池中的相应触发器。例如，如果您删除身份验证后触发器，则必须在相应用户池中将 **Post authentication**（身份验证后）触发器设置为 **none**（无）。
+ 如果您的 Lambda 函数没有向 Amazon Cognito 返回请求和响应参数，或者返回错误，则身份验证事件将无法成功。您可以在函数中返回错误，以阻止用户注册、身份验证、令牌生成或其身份验证流程中任何其他调用 Lambda 触发器的阶段。

  托管登录将返回 Lambda 触发器生成的错误作为登录提示上方的错误文本。Amazon Cognito 用户池 API 以 `[trigger] failed with error [error text from response]` 格式返回触发器错误。最佳做法是，仅在 Lambda 函数中生成您希望用户看到的错误。使用输出方法`print()`，例如将任何敏感信息或调试信息 CloudWatch 记录到 Logs 中。有关示例，请参阅[注册前示例：如果用户名少于五个字符，则拒绝注册](user-pool-lambda-pre-sign-up.md#aws-lambda-triggers-pre-registration-example-3)。
+ 您可以在另一个函数中添加 Lambda 函数 AWS 账户 作为用户池的触发器。您必须使用[CreateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html)和 [UpdateUserPool](https://docs.aws.amazon.com/)API 操作添加跨账户触发器，或者在和中 CloudFormation 添加等效操作。 AWS CLI您无法在中添加跨账户功能。 AWS 管理控制台
+ 当您在 Amazon Cognito 控制台中添加 Lambda 触发器时，Amazon Cognito 会向您的函数添加一个基于资源的策略，允许您的用户池调用该函数。当您在 Amazon Cognito 控制台之外创建 Lambda 触发器（包括跨账户函数）时，您必须向 Lambda 函数的基于资源的策略添加权限。您添加的权限必须允许 Amazon Cognito 代表您的用户池调用函数。您可以[从 Lambda 控制台添加权限或使用 Lambd](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html) a API 操作。[AddPermission](https://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html)

**Lambda 基于资源的策略示例**  
以下 Lambda 基于资源的策略示例授予 Amazon Cognito 有限调用 Lambda 函数的能力。Amazon Cognito 只能在代表 `aws:SourceArn` 中的用户池和 `aws:SourceAccount` 条件中的账户时才能调用函数。

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

****  

  ```
  {
      "Version":"2012-10-17",		 	 	 
      "Id": "default",
      "Statement": [
          {
              "Sid": "LambdaCognitoIdpTrust",
              "Effect": "Allow",
              "Principal": {
                  "Service": "cognito-idp.amazonaws.com"
              },
              "Action": "lambda:InvokeFunction",
              "Resource": "arn:aws:lambda:us-east-1:111122223333:function:MyFunction",
              "Condition": {
                  "StringEquals": {
                      "AWS:SourceAccount": "111122223333"
                  },
                  "ArnLike": {
                      "AWS:SourceArn": "arn:aws:cognito-idp:us-east-1:111122223333:userpool/us-east-1_EXAMPLE"
                  }
              }
          }
      ]
  }
  ```

------

## 添加用户池 Lambda 触发器
<a name="triggers-working-with-lambda"></a>

**使用控制台添加用户池 Lambda 触发器**

1. 使用 [Lambda 控制台](https://console.aws.amazon.com/lambda/home)创建 Lambda 函数。有关 Lambda 函数的更多信息，请参阅《AWS Lambda 开发人员指南》[https://docs.aws.amazon.com/lambda/latest/dg/](https://docs.aws.amazon.com/lambda/latest/dg/)。

1. 转到 [Amazon Cognito 控制台](https://console.aws.amazon.com/cognito/home)，然后选择 **User Pools**（用户池）。

1. 从列表中选择一个现有用户池，或[创建一个用户池](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-as-user-directory.html)。

1. 选择**扩展**菜单并找到 **Lambda 触发器**。

1. 选择 **Add a Lambda trigger**（添加 Lambda 触发器）。

1. 基于您希望自定义的身份验证阶段，选择 Lambda 触发器 **Category**（类别）。

1. 选择 “**分配 Lambda 函数**”，然后选择与您的用户池 AWS 区域 相同的函数。
**注意**  
如果您的 AWS Identity and Access Management (IAM) 证书有权更新 Lambda 函数，则 Amazon Cognito 会添加基于 Lambda 资源的策略。通过此政策，Amazon Cognito 可以调用您选择的函数。如果登录凭证没有足够的 IAM 权限，则必须单独更新基于资源的策略。有关更多信息，请参阅 [有关 Lambda 触发器的需知信息](#important-lambda-considerations)。

1. 选择**保存更改**。

1. 您可以在 Lambda 控制台 CloudWatch 中使用来记录您的 Lambda 函数。有关更多信息，请参阅[访问 Lambda 的 CloudWatch 日志](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-functions-logs.html)。

## 用户池 Lambda 触发器事件
<a name="cognito-user-pools-lambda-trigger-event-parameter-shared"></a>

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，Lambda 函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。如果您的函数返回未经修改的输入事件，Amazon Cognito 将继续执行默认行为。下面显示了所有 Lambda 触发器输入事件的通用参数。有关特定于触发器的事件语法，请查阅本指南中各触发器对应章节中的事件架构。

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

```
{
    "version": "string",
    "triggerSource": "string",
    "region": AWSRegion,
    "userPoolId": "string",
    "userName": "string",
    "callerContext": 
        {
            "awsSdkVersion": "string",
            "clientId": "string"
        },
    "request":
        {
            "userAttributes": {
                "string": "string",
                ....
            }
        },
    "response": {}
}
```

------

## 用户池 Lambda 触发器通用参数
<a name="cognito-user-pools-lambda-trigger-syntax-shared"></a>

**version**  
您的 Lambda 函数的版本号。

**triggerSource**  
触发 Lambda 函数的事件的名称。有关每个 triggerSource 的说明，请参阅[将 Lambda 触发器连接到用户池功能操作](#working-with-lambda-trigger-sources)。

**region**  
 AWS 区域 作为一个`AWSRegion`实例。

**userPoolId**  
用户池的 ID。

**userName**  
当前用户的用户名。

**callerContext**  
有关请求和代码环境的元数据。它包含字段**awsSdkVersion**和**客户端 ID**。    
**awsSdkVersion**  
生成请求的 AWS SDK 版本。  
****clientId****  
用户池应用程序客户端的 ID。

**request**  
您的用户的 API 请求的详细信息。它包括以下字段以及触发器特定的任何请求参数。例如，Amazon Cognito 发送到预身份验证触发器的事件也将包含一个 `userNotFound` 参数。当您的用户尝试使用未注册的用户名登录时，您可以处理此参数的值以执行自定义操作。    
**userAttributes**  
用户属性名称和值的一个或多个键值对，例如 `"email": "john@example.com"`。

**响应**  
此参数在原始请求中不包含任何信息。Lambda 函数必须将整个事件返回给 Amazon Cognito，并将任何返回参数添加到 `response`。要查看您的函数可以包含哪些返回参数，请参阅要使用的触发器的文档。

## 客户端元数据
<a name="working-with-lambda-trigger-client-metadata"></a>

您可以在 API 操作和[令牌端点](token-endpoint.md)请求中向 Lambda 触发器函数提交自定义参数。通过客户端元数据，您的应用程序可以收集有关请求来源环境的额外信息。当您将客户端元数据传递给您的 Lambda 函数时，它们可以处理这些附加数据，并将其用于日志记录或自定义身份验证流。客户端元数据是您选择和设计的字符串对，采用 JSON 键值格式。

**客户端元数据使用案例示例**
+ 在注册时将地理位置数据传递给[注册前触发器](user-pool-lambda-pre-sign-up.md)，并阻止来自非预期位置的登录请求。
+ 将租户 ID 数据传递给[自定义质询触发器](user-pool-lambda-challenge.md)，并向来自不同业务单位的客户发出不同的质询。
+ 将用户的令牌传递给[令牌生成前触发器](user-pool-lambda-pre-token-generation.md)，并生成日志，记录 M2M 请求所代表的主体。有关示例请求，请参阅[基本授权的客户端凭证POST 正文授权的客户端凭证](token-endpoint.md#exchanging-client-credentials-for-an-access-token-in-request-body)。

以下是向注册前触发器传递客户端元数据的一个示例。

------
#### [ SignUp request ]

以下是一个包含客户端元数据的示例[SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html#CognitoUserPools-SignUp-request-ValidationData)请求，Amazon Cognito 会将其传递给注册前触发器。

```
POST HTTP/1.1
Host: cognito-idp.us-east-1.amazonaws.com
X-Amz-Date: 20230613T200059Z
Accept-Encoding: gzip, deflate, br
X-Amz-Target: AWSCognitoIdentityProviderService.SignUp
User-Agent: <UserAgentString>
Authorization: AWS4-HMAC-SHA256 Credential=<Credential>, SignedHeaders=<Headers>, Signature=<Signature>
Content-Length: <PayloadSizeBytes>

{
    "ClientId": "1example23456789",
    "Username": "mary_major",
    "Password": "<Password>",
    "SecretHash": "<Secret hash>",
    "ClientMetadata": { 
        "IpAddress" : "192.0.2.252",
        "GeoLocation" : "Netherlands (Kingdom of the) [NL]"
    }
    "UserAttributes": [
        {
            "Name": "name",
            "Value": "Mary"
        },
        {
            "Name": "email",
            "Value": "mary_major@example.com"
        },
        {
            "Name": "phone_number",
            "Value": "+12065551212"
        }
    ],
}
```

------
#### [ Lambda trigger input event ]

该请求会生成以下请求正文，并发送给您的注册前函数。

```
{
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "1example23456789"
    },
    "region": "us-west-2",
    "request": {
        "clientMetadata": {
            "GeoLocation": "Netherlands (Kingdom of the) [NL]",
            "IpAddress": "192.0.2.252"
        },
        "userAttributes": {
            "email": "mary_major@example.com",
            "name": "Mary",
            "phone_number": "+12065551212"
        },
        "validationData": null
    },
    "response": {
        "autoConfirmUser": false,
        "autoVerifyEmail": false,
        "autoVerifyPhone": false
    },
    "triggerSource": "PreSignUp_SignUp",
    "userName": "mary_major2",
    "userPoolId": "us-west-2_EXAMPLE",
    "version": "1"
}
```

------

**machine-to-machine(M2M) 客户端凭证的客户端元数据**  
您可以在 M2M 请求中传递[客户端元数据](#working-with-lambda-trigger-client-metadata)。客户端元数据是来自用户或应用程序环境的附加信息，可影响[令牌生成前 Lambda 触发器](user-pool-lambda-pre-token-generation.md)的结果。在使用用户委托人的身份验证操作中，您可以将客户端元数据传递给 [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html)API 请求正文中的令牌生成前触发器。[AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html)由于应用程序通过直接向 [令牌端点](token-endpoint.md) 发出请求来执行为 M2M 生成访问令牌的流程，因此它们的模型不同。在客户端凭证令牌请求的 POST 正文中，传递一个 `aws_client_metadata` 参数，其值为客户端元数据对象经 URL 编码（`x-www-form-urlencoded`）后的字符串。有关示例请求，请参阅[基本授权的客户端凭证POST 正文授权的客户端凭证](token-endpoint.md#exchanging-client-credentials-for-an-access-token-in-request-body)。以下是传递键值对 `{"environment": "dev", "language": "en-US"}` 的参数的示例。

```
aws_client_metadata=%7B%22environment%22%3A%20%22dev%22,%20%22language%22%3A%20%22en-US%22%7D
```

**临时用户属性：`validationData`**  
一些身份验证操作也有一个 `validationData` 参数。与客户端元数据一样，这是一个将 Amazon Cognito 不会自动收集的外部信息传递给 Lambda 触发器的机会。验证数据字段旨在为您的 Lambda 函数提供注册和登录操作中的其他用户上下文。 [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html#CognitoUserPools-SignUp-request-ValidationData)并[AdminCreateUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html#CognitoUserPools-AdminCreateUser-request-ValidationData)传递`validationData`到[注册前的触发器](user-pool-lambda-pre-sign-up.md)。 [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html#CognitoUserPools-InitiateAuth-request-ClientMetadata)并像`ClientMetadata`在输入事件`validationData`中一样将 API 请求正文[AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html#CognitoUserPools-AdminInitiateAuth-request-ClientMetadata)传递给[预身份验证](user-pool-lambda-pre-authentication.md)并[迁移用户](user-pool-lambda-migrate-user.md)触发器。

要将 API 操作映射到它们可以将客户端元数据传递到的函数，请参阅后面有关触发器源的章节。

## 将 API 操作连接到 Lambda 触发器
<a name="lambda-triggers-by-event"></a>

以下部分介绍 Amazon Cognito 从您的用户池中的活动调用的 Lambda 触发器。

当您的应用程序通过 Amazon Cognito 用户池 API、托管登录或用户池端点登录用户时，Amazon Cognito 会根据会话上下文调用您的 Lambda 函数。有关 Amazon Cognito 用户池 API 和用户池端点的更多信息，请参阅[了解 API、OIDC 和托管登录页面身份验证](authentication-flows-public-server-side.md#user-pools-API-operations)。以下各节中的表格描述了导致 Amazon Cognito 调用函数的事件，以及 Amazon Cognito 在请求中包含的 `triggerSource` 字符串。

**Topics**
+ [Amazon Cognito API 中的 Lambda 触发器](#lambda-triggers-native-users-native-api)
+ [托管登录中的 Amazon Cognito 本地用户的 Lambda 触发器](#lambda-triggers-native-users-hosted-UI)
+ [针对联合身份用户的 Lambda 触发器](#lambda-triggers-for-federated-users)

### Amazon Cognito API 中的 Lambda 触发器
<a name="lambda-triggers-native-users-native-api"></a>

下表描述了 Lambda 触发器的源字符串，当您的应用程序创建、登录或更新本地用户时，Amazon Cognito 可以调用这些触发器。


**Amazon Cognito API 中的本地用户触发器来源**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html)

### 托管登录中的 Amazon Cognito 本地用户的 Lambda 触发器
<a name="lambda-triggers-native-users-hosted-UI"></a>

下表描述了 Lambda 触发器的源字符串，当本地用户使用托管登录来登录到您的用户池时，Amazon Cognito 可以调用这些触发器。


**托管登录中的本地用户触发器源**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html)

### 针对联合身份用户的 Lambda 触发器
<a name="lambda-triggers-for-federated-users"></a>

您可以使用以下 Lambda 触发器，为使用联合身份提供商登录的用户自定义用户池工作流。

**注意**  
联合用户可以使用托管登录进行登录，也可以生成对[对端点授权](authorization-endpoint.md)的请求，以静默方式将它们重新导向到其身份提供者登录页面。您无法使用 Amazon Cognito 用户池 API 登录联合用户。


**联合身份用户触发器源**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html)

联合身份登录不会在您的用户池中调用任何 [自定义身份验证质询 Lambda 触发器](user-pool-lambda-challenge.md)、[迁移用户 Lambda 触发器](user-pool-lambda-migrate-user.md)、[自定义消息 Lambda 触发器](user-pool-lambda-custom-message.md) 或者[自定义发件人 Lambda 触发器](user-pool-lambda-custom-sender-triggers.md)。

## 将 Lambda 触发器连接到用户池功能操作
<a name="working-with-lambda-trigger-sources"></a>

每个 Lambda 触发器都在您的用户池中发挥功能作用。例如，触发器可以修改您的注册流程，或添加自定义身份验证质询。Amazon Cognito 发送到 Lambda 函数的事件可以反映构成该函数角色的多个操作之一。例如，当您的用户注册时以及当您创建用户时，Amazon Cognito 会调用预注册触发器。同一功能角色的每个不同案例都有其自身的 `triggerSource` 值。您的 Lambda 函数可以根据调用该函数的操作以不同的方式处理传入事件。

当事件对应于触发器源时，Amazon Cognito 还会调用所有分配的函数。例如，当用户登录到您分配了迁移用户和预身份验证触发器的用户池时，他们会同时激活这两个触发器。


**注册、确认和登录 (身份验证) 触发器**  

| 触发器 | triggerSource 值 | 事件 | 
| --- | --- | --- | 
| 注册前 | PreSignUp\$1SignUp | 注册前。 | 
| 注册前 | PreSignUp\$1AdminCreateUser | 在管理员创建新用户时做好注册准备。 | 
| 注册前 | PreSignUp\$1ExternalProvider | 适用于外部身份提供商的注册前。 | 
| 发布确认 | PostConfirmation\$1ConfirmSignUp | 注册后确认。 | 
| 确认后 | PostConfirmation\$1ConfirmForgotPassword | 忘记密码后确认。 | 
| 身份验证前 | PreAuthentication\$1Authentication | 身份验证前。 | 
| 身份验证后 | PostAuthentication\$1Authentication | 身份验证后。 | 


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

| 触发器 | triggerSource 值 | 事件 | 
| --- | --- | --- | 
| 定义身份验证质询 | DefineAuthChallenge\$1Authentication | 定义身份验证质询。 | 
| 创建身份验证质询 | CreateAuthChallenge\$1Authentication | 创建身份验证质询。 | 
| 验证身份验证质询 | VerifyAuthChallengeResponse\$1Authentication | 验证身份验证质询响应。 | 


**联邦触发器**  

| 触发器 | triggerSource 值 | 事件 | 
| --- | --- | --- | 
| 入站联邦 | InboundFederation\$1ExternalProvider | 入站联合。 | 


**令牌生成前触发器**  

| 触发器 | triggerSource 值 | 事件 | 
| --- | --- | --- | 
| 令牌生成前 | TokenGeneration\$1HostedAuth |  Amazon Cognito 从您的托管登录页面对用户进行身份验证。 | 
| 令牌生成前 | TokenGeneration\$1Authentication | 用户身份验证或令牌刷新已完成。 | 
| 令牌生成前 | TokenGeneration\$1NewPasswordChallenge | 管理员创建用户。当用户必须更改临时密码时，Amazon Cognito 调用此项。 | 
| 令牌生成前 | TokenGeneration\$1AuthenticateDevice | 结束用户设备身份验证。 | 
| 令牌生成前 | TokenGeneration\$1RefreshTokens | 用户尝试刷新身份和访问令牌时调用。 | 


**迁移用户触发器**  

| 触发器 | triggerSource 值 | 事件 | 
| --- | --- | --- | 
| 用户迁移 | UserMigration\$1Authentication | 用户登录时进行迁移。 | 
| 用户迁移 | UserMigration\$1ForgotPassword | 忘记密码流程中的用户迁移。 | 


**自定义消息触发器**  

| 触发器 | triggerSource 值 | 事件 | 
| --- | --- | --- | 
| 自定义消息 | CustomMessage\$1SignUp | 用户在您的用户池中注册时的自定义消息。 | 
| 自定义消息 | CustomMessage\$1AdminCreateUser | 当您创建用户作为管理员并且 Amazon Cognito 向他们发送临时密码时的自定义消息。 | 
| 自定义消息 | CustomMessage\$1ResendCode | 现有用户请求新的确认码时的自定义消息。 | 
| 自定义消息 | CustomMessage\$1ForgotPassword | 用户请求重置密码时的自定义消息。 | 
| 自定义消息 | CustomMessage\$1UpdateUserAttribute | 用户更改其电子邮件地址或电话号码并且 Amazon Cognito 发送验证码时的自定义消息。 | 
| 自定义消息 | CustomMessage\$1VerifyUserAttribute | 用户添加电子邮件地址或电话号码并且 Amazon Cognito 发送验证码时的自定义消息。 | 
| 自定义消息 | CustomMessage\$1Authentication | 配置了 SMS MFA 的用户登录时的自定义消息。 | 


**自定义发件人触发器**  

| 触发器 | triggerSource 值 | 事件 | 
| --- | --- | --- | 
| 自定义发件人 |  `CustomEmailSender_SignUp` `CustomSmsSender_SignUp`  | 用户在您的用户池中注册。 | 
| 自定义发件人 |  `CustomEmailSender_AdminCreateUser` `CustomSmsSender_AdminCreateUser`  | 您以管理员身份创建用户并且 Amazon Cognito 向他们发送临时密码。 | 
| 自定义发件人 |  `CustomEmailSender_ForgotPassword` `CustomSmsSender_ForgotPassword`  | 用户请求重置密码。 | 
| 自定义发件人 |  `CustomEmailSender_UpdateUserAttribute` `CustomSmsSender_UpdateUserAttribute`  | 用户更改其电子邮件地址或电话号码并且 Amazon Cognito 发送验证码。 | 
| 自定义发件人 |  `CustomEmailSender_VerifyUserAttribute` `CustomSmsSender_VerifyUserAttribute`  | 用户添加电子邮件地址或电话号码并且 Amazon Cognito 发送验证码。 | 
| 自定义发件人 |  `CustomEmailSender_Authentication` `CustomSmsSender_Authentication`  | 配置了短信、电子邮件 MFA 或 OTP 的用户登录。 | 
| 自定义发件人 | CustomEmailSender\$1AccountTakeOverNotification | 您的威胁防护设置对用户的登录尝试采取自动操作并且针对风险级别的操作包括通知。 | 

# 注册前 Lambda 触发器
<a name="user-pool-lambda-pre-sign-up"></a>

您可能想要在具有自助注册选项的用户池中自定义注册流程。注册前触发器的一些常见用途包括对新用户进行自定义分析和记录、应用安全和治理标准，或者将第三方 IdP 的用户链接到[整合的用户配置文件](cognito-user-pools-identity-federation-consolidate-users.md)。您可能还有不需要进行[验证和确认](signing-up-users-in-your-app.md)的可信用户。

在 Amazon Cognito 完成创建新的[本地](cognito-terms.md#terms-localuser)用户或[联合](cognito-terms.md#terms-federateduser)用户之前不久，它会激活注册前 Lambda 函数。发送给此函数的请求对象中的 `userAttributes` 包含本地用户注册时提供的属性，或已成功从联合用户的身份提供者属性映射过来的属性。在使用可信[身份提供商](amazon-cognito-user-pools-authentication-flow-methods.md#amazon-cognito-user-pools-authentication-flow-methods-federated)进行自助注册[SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html)或首次登录时，以及使用创建用户时，您的用户池会调用此触发器。[AdminCreateUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html)在注册过程中，您可以使用此函数，利用自定义逻辑来分析登录事件，并修改或拒绝新用户。

**Topics**
+ [注册前 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-pre-signup)
+ [注册前示例：从注册的域自动确认用户](#aws-lambda-triggers-pre-registration-example)
+ [注册前示例：自动确认和自动验证所有用户](#aws-lambda-triggers-pre-registration-example-2)
+ [注册前示例：如果用户名少于五个字符，则拒绝注册](#aws-lambda-triggers-pre-registration-example-3)

## 注册前 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-pre-signup"></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",
            . . .
        },
        "validationData": {
            "string": "string",
            . . .
         },
        "clientMetadata": {
            "string": "string",
            . . .
         }
    },

    "response": {
        "autoConfirmUser": "boolean",
        "autoVerifyPhone": "boolean",
        "autoVerifyEmail": "boolean"
    }
}
```

------

### 注册前请求参数
<a name="cognito-user-pools-lambda-trigger-syntax-pre-signup-request"></a>

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

**validationData**  
一个或多个包含用户属性数据的键值对，您的应用程序在创建新用户的请求中将这些数据传递给 Amazon Cognito。在您[AdminCreateUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html)或 [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html)API 请求的 ValidationData 参数中将此信息发送到您的 Lambda 函数。  
Amazon Cognito 不会将你的 ValidationData 数据设置为你创建的用户的属性。 ValidationData 是您为注册前 Lambda 触发器而提供的临时用户信息。

**clientMetadata**  
一个或多个键值对，您可以将其作为自定义输入内容提供给为注册前触发器指定的 Lambda 函数。您可以使用以下 API 操作中的 ClientMetadata参数将此数据传递给您的 Lambda 函数：[AdminCreateUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html)、[AdminRespondToAuthChallenge[ForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ForgotPassword.html)](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html)、和。[SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html)

### 注册前响应参数
<a name="cognito-user-pools-lambda-trigger-syntax-pre-signup-response"></a>

在响应中，如果您想要自动确认用户，则您可以将 `autoConfirmUser` 设置为 `true`。您可以将 `autoVerifyEmail` 设置为 `true`，以自动验证用户的电子邮件。您可以将 `autoVerifyPhone` 设置为 `true`，以自动验证用户的电话号码。

**注意**  
`AdminCreateUser` API 触发注册前 Lambda 函数时，Amazon Cognito 会忽略响应参数 `autoVerifyPhone`、`autoVerifyEmail` 和 `autoConfirmUser`。

**autoConfirmUser**  
设置为 `true` 以自动确认用户，否则设置为 `false`。

**autoVerifyEmail**  
设置为 `true` 可以设置为所注册用户已通过验证的电子邮件地址，否则为 `false`。如果 `autoVerifyEmail` 设置为 `true`，则 `email` 属性必须具有有效的非空值。否则将出现错误，用户将无法完成注册。  
如果选择 `email` 属性作为别名，则在设置了 `autoVerifyEmail` 时将为用户的电子邮件地址创建别名。如果已存在具有该电子邮件地址的别名，则别名将移动到新用户，以前用户的电子邮件地址将标记为未验证。有关更多信息，请参阅 [自定义登录属性](user-pool-settings-attributes.md#user-pool-settings-aliases)。

**autoVerifyPhone**  
设置为 `true` 可以设置为所注册用户已通过验证的电话号码，否则为 `false`。如果 `autoVerifyPhone` 设置为 `true`，则 `phone_number` 属性必须具有有效的非空值。否则将出现错误，用户将无法完成注册。  
如果选择 `phone_number` 属性作为别名，则在设置了 `autoVerifyPhone` 时将为用户的电话号码创建别名。如果已存在具有该电话号码的别名，则别名将移动到新用户，以前用户的电话号码将标记为未验证。有关更多信息，请参阅 [自定义登录属性](user-pool-settings-attributes.md#user-pool-settings-aliases)。

## 注册前示例：从注册的域自动确认用户
<a name="aws-lambda-triggers-pre-registration-example"></a>

这是 Lambda 触发器代码的示例。在 Amazon Cognito 处理注册请求之前不久，注册前触发器会被调用。它使用自定义属性 **custom:domain** 自动确认来自特定电子邮件域的新用户。任何不在自定义域中的新用户都将添加到用户池，但不会自动确认。

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

```
export const handler = async (event, context, callback) => {
  // Set the user pool autoConfirmUser flag after validating the email domain
  event.response.autoConfirmUser = false;

  // Split the email address so we can compare domains
  var address = event.request.userAttributes.email.split("@");

  // This example uses a custom attribute "custom:domain"
  if (event.request.userAttributes.hasOwnProperty("custom:domain")) {
    if (event.request.userAttributes["custom:domain"] === address[1]) {
      event.response.autoConfirmUser = true;
    }
  }

  // Return to Amazon Cognito
  callback(null, event);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    # It sets the user pool autoConfirmUser flag after validating the email domain
    event['response']['autoConfirmUser'] = False

    # Split the email address so we can compare domains
    address = event['request']['userAttributes']['email'].split('@')

    # This example uses a custom attribute 'custom:domain'
    if 'custom:domain' in event['request']['userAttributes']:
        if event['request']['userAttributes']['custom:domain'] == address[1]:
            event['response']['autoConfirmUser'] = True

    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
    "request": {
        "userAttributes": {
            "email": "testuser@example.com",
            "custom:domain": "example.com"
        }
    },
    "response": {}
}
```

------

## 注册前示例：自动确认和自动验证所有用户
<a name="aws-lambda-triggers-pre-registration-example-2"></a>

此示例确认所有用户并将用户的 `email` 和 `phone_number` 属性设置为“已验证”（如果该属性存在）。此外，如果启用了别名，当设置了自动验证时，将为 `phone_number` 和 `email` 创建别名。

**注意**  
如果已存在具有相同电话号码的别名，则别名将移动到新用户，以前用户的 `phone_number` 将标记为未验证。电子邮件地址也是如此。为了防止这种情况发生，您可以使用用户池 [ListUsers API](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ListUsers.html) 来查看是否有现有用户已在使用新用户的电话号码或电子邮件地址作为别名。

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

```
exports.handler = (event, context, callback) => {
  // Confirm the user
  event.response.autoConfirmUser = true;

  // Set the email as verified if it is in the request
  if (event.request.userAttributes.hasOwnProperty("email")) {
    event.response.autoVerifyEmail = true;
  }

  // Set the phone number as verified if it is in the request
  if (event.request.userAttributes.hasOwnProperty("phone_number")) {
    event.response.autoVerifyPhone = true;
  }

  // Return to Amazon Cognito
  callback(null, event);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    # Confirm the user
    event['response']['autoConfirmUser'] = True

    # Set the email as verified if it is in the request
    if 'email' in event['request']['userAttributes']:
        event['response']['autoVerifyEmail'] = True

    # Set the phone number as verified if it is in the request
    if 'phone_number' in event['request']['userAttributes']:
        event['response']['autoVerifyPhone'] = True

    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
  "request": {
    "userAttributes": {
      "email": "user@example.com",
      "phone_number": "+12065550100"
    }
  },
  "response": {}
}
```

------

## 注册前示例：如果用户名少于五个字符，则拒绝注册
<a name="aws-lambda-triggers-pre-registration-example-3"></a>

此示例检查注册请求中用户名的长度。如果用户输入的名称长度少于五个字符，则该示例将返回错误。

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

```
export const handler = (event, context, callback) => {
    // Impose a condition that the minimum length of the username is 5 is imposed on all user pools.
    if (event.userName.length < 5) {
        var error = new Error("Cannot register users with username less than the minimum length of 5");
        // Return error to Amazon Cognito
        callback(error, event);
    }
    // Return to Amazon Cognito
    callback(null, event);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    if len(event['userName']) < 5:
        raise Exception("Cannot register users with username less than the minimum length of 5")
    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
  "userName": "rroe",
  "response": {}
}
```

------

# 确认后 Lambda 触发器
<a name="user-pool-lambda-post-confirmation"></a>

Amazon Cognito 会在注册用户确认其用户账户后调用此触发器。在您的确认后 Lambda 函数中，您可以发送自定义消息或添加自定义 API 请求。例如，您可以查询外部系统并为用户填充其他属性。Amazon Cognito 仅对在您的用户池中注册的用户调用此触发器，而不会针对您使用管理员凭证创建的用户账户调用此触发器。

请求包含已确认用户的当前属性。您的用户池在[ConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmSignUp.html)、[AdminConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminConfirmSignUp.html)和上调用您的帖子确认功能。[ConfirmForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmForgotPassword.html)当用户在[托管登录](cognito-user-pools-managed-login.md)中确认注册或密码重置时，此触发器也会运行。

**Topics**
+ [确认后 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-post-confirmation)
+ [确认后示例](#aws-lambda-triggers-post-confirmation-example)

## 确认后 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-post-confirmation"></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",
                . . .
            },
            "clientMetadata": {
            	"string": "string",
            	. . .
            }
        },
    "response": {}
}
```

------

### 确认后请求参数
<a name="cognito-user-pools-lambda-trigger-syntax-post-confirmation-request"></a>

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

**clientMetadata**  
一个或多个键值对，您可以将其作为自定义输入内容提供给为确认后触发器指定的 Lambda 函数。您可以使用以下 API 操作中的 ClientMetadata 参数将此数据传递给您的 Lambda 函数：[AdminConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminConfirmSignUp.html)、[ConfirmForgotPassword[ConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmSignUp.html)](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmForgotPassword.html)、和。[SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html)

### 确认后响应参数
<a name="cognito-user-pools-lambda-trigger-syntax-post-confirmation-response"></a>

预计响应中没有其他返回信息。

## 确认后示例
<a name="aws-lambda-triggers-post-confirmation-example"></a>

此示例 Lambda 函数将使用 Amazon SES 向用户发送确认电子邮件。有关更多信息，请参阅 [Amazon Simple Email Service 开发人员指南](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/)。

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

```
// Import required AWS SDK clients and commands for Node.js. Note that this requires
// the `@aws-sdk/client-ses` module to be either bundled with this code or included
// as a Lambda layer.
import { SES, SendEmailCommand } from "@aws-sdk/client-ses";
const ses = new SES();

const handler = async (event) => {
  if (event.request.userAttributes.email) {
    await sendTheEmail(
      event.request.userAttributes.email,
      `Congratulations ${event.userName}, you have been confirmed.`,
    );
  }
  return event;
};

const sendTheEmail = async (to, body) => {
  const eParams = {
    Destination: {
      ToAddresses: [to],
    },
    Message: {
      Body: {
        Text: {
          Data: body,
        },
      },
      Subject: {
        Data: "Cognito Identity Provider registration completed",
      },
    },
    // Replace source_email with your SES validated email address
    Source: "<source_email>",
  };
  try {
    await ses.send(new SendEmailCommand(eParams));
  } catch (err) {
    console.log(err);
  }
};

export { handler };
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
    "request": {
        "userAttributes": {
            "email": "user@example.com",
            "email_verified": true
        }
    },
    "response": {}
}
```

------

# 身份验证前 Lambda 触发器
<a name="user-pool-lambda-pre-authentication"></a>

当用户尝试登录时，Amazon Cognito 会调用此触发器，以便您可以创建用于执行准备操作的自定义验证。例如，您可以拒绝身份验证请求或将会话数据记录到外部系统。

**注意**  
此 Lambda 触发器在用户不存在时不会激活，除非将用户池应用程序客户端的 `PreventUserExistenceErrors` 设置设为 `ENABLED`。续订现有身份验证会话也不会激活此触发器。

**Topics**
+ [流程概述](#user-pool-lambda-pre-authentication-1)
+ [身份验证前 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-pre-auth)
+ [身份验证前示例](#aws-lambda-triggers-pre-authentication-example)

## 流程概述
<a name="user-pool-lambda-pre-authentication-1"></a>

![\[身份验证前 Lambda 触发器 – 客户端流程\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/images/lambda-pre-authentication-1.png)


该请求包含来自 `ClientMetadata` 值的客户端验证数据，该值由应用程序传递到用户池 `InitiateAuth` 和 `AdminInitiateAuth` API 操作。

有关更多信息，请参阅 [身份验证会话示例](authentication.md#amazon-cognito-user-pools-authentication-flow)。

## 身份验证前 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-pre-auth"></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",
            . . .
        },
        "validationData": {
            "string": "string",
            . . .
        },
        "userNotFound": boolean
    },
    "response": {}
}
```

------

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

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

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

**validationData**  
一个或多个键/值对，包含用户的登录请求中的验证数据。要将此数据传递给您的 Lambda 函数，请使用[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)API 操作中的 ClientMetadata 参数。

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

Amazon Cognito 不处理您的函数在响应中返回的任何附加信息。您的函数可以返回错误以拒绝登录尝试，或者使用 API 操作来查询和修改资源。

## 身份验证前示例
<a name="aws-lambda-triggers-pre-authentication-example"></a>

此示例函数阻止用户使用特定的应用程序客户端登录到您的用户池。由于预身份验证 Lambda 函数不会在您的用户有现有会话时调用，因此，此函数仅阻止使用您想要屏蔽的应用程序客户端 ID 的*新*会话。

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

```
const handler = async (event) => {
  if (
    event.callerContext.clientId === "user-pool-app-client-id-to-be-blocked"
  ) {
    throw new Error("Cannot authenticate users from this user pool app client");
  }

  return event;
};

export { handler };
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    if event['callerContext']['clientId'] == "<user pool app client id to be blocked>":
        raise Exception("Cannot authenticate users from this user pool app client")

    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
    "callerContext": {
        "clientId": "<user pool app client id to be blocked>"
    },
    "response": {}
}
```

------

# 身份验证后 Lambda 触发器
<a name="user-pool-lambda-post-authentication"></a>

身份验证后触发器不会更改用户的身份验证流程。Amazon Cognito 会在身份验证完成后，在用户收到令牌之前调用此 Lambda。当您想要添加身份验证事件的自定义后处理时（例如，将在下次登录时反映的日志记录或用户配置文件调整），请添加身份验证后触发器。

不将请求正文返回给 Amazon Cognito 的身份验证后 Lambda 仍会导致身份验证无法完成。有关更多信息，请参阅 [有关 Lambda 触发器的需知信息](cognito-user-pools-working-with-lambda-triggers.md#important-lambda-considerations)。

**Topics**
+ [身份验证流概述](#user-pool-lambda-post-authentication-1)
+ [身份验证后 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-post-auth)
+ [身份验证后示例](#aws-lambda-triggers-post-authentication-example)

## 身份验证流概述
<a name="user-pool-lambda-post-authentication-1"></a>

![\[身份验证后 Lambda 触发器 – 客户端流程\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/images/lambda-post-authentication-1.png)


有关更多信息，请参阅 [身份验证会话示例](authentication.md#amazon-cognito-user-pools-authentication-flow)。

## 身份验证后 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-post-auth"></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",
             . . .
         },
         "newDeviceUsed": boolean,
         "clientMetadata": {
             "string": "string",
             . . .
            }
        },
    "response": {}
}
```

------

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

**newDeviceUsed**  
此标记指示用户是否已在新设备上登录。Amazon Cognito 仅在用户池的记住的设备值设置为 `Always` 或 `User Opt-In` 时设置此标记。

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

**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-post-auth-response"></a>

Amazon Cognito 不需要响应中任何额外的返回信息。您的函数可以使用 API 操作来查询和修改资源，或者将事件元数据记录到外部系统。

## 身份验证后示例
<a name="aws-lambda-triggers-post-authentication-example"></a>

此身份验证后示例 Lambda 函数将成功登录后的数据发送到日志。 CloudWatch 

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

```
const handler = async (event) => {
  // Send post authentication data to Amazon CloudWatch logs
  console.log("Authentication successful");
  console.log("Trigger function =", event.triggerSource);
  console.log("User pool = ", event.userPoolId);
  console.log("App client ID = ", event.callerContext.clientId);
  console.log("User ID = ", event.userName);

  return event;
};

export { handler };
```

------
#### [ Python ]

```
import os
def lambda_handler(event, context):

    # Send post authentication data to Cloudwatch logs
    print ("Authentication successful")
    print ("Trigger function =", event['triggerSource'])
    print ("User pool = ", event['userPoolId'])
    print ("App client ID = ", event['callerContext']['clientId'])
    print ("User ID = ", event['userName'])

    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
  "triggerSource": "testTrigger",
  "userPoolId": "testPool",
  "userName": "testName",
  "callerContext": {
      "clientId": "12345"
  },
  "response": {}
}
```

------

# 入站联邦 Lambda 触发器
<a name="user-pool-lambda-inbound-federation"></a>

在使用外部身份提供商进行身份验证的过程中，入站联合身份触发器会转换联合用户属性。当用户通过配置的身份提供商进行身份验证时，此触发器允许您通过拦截和转换身份验证过程中的数据来修改来自外部 SAML 和 OIDC 提供商的响应，从而对 Amazon Cognito 用户池处理联合用户及其属性的方式进行编程控制。

在创建新用户或更新现有联合用户配置文件之前，使用此触发器添加、覆盖或隐藏属性。此触发器接收原始身份提供者属性作为输入，并返回 Amazon Cognito 应用于用户个人资料的修改属性。

**Topics**
+ [流程概述](#cognito-user-pools-lambda-trigger-inbound-federation-flow)
+ [入站联邦 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-inbound-federation)
+ [入站联盟示例：群组成员资格管理](#aws-lambda-triggers-inbound-federation-example-groups)
+ [入站联合示例：截断大型属性](#aws-lambda-triggers-inbound-federation-example-truncate)
+ [入站联合示例：记录联合事件](#aws-lambda-triggers-inbound-federation-example-logging)

## 流程概述
<a name="cognito-user-pools-lambda-trigger-inbound-federation-flow"></a>

当用户通过外部身份提供商进行身份验证时，Amazon Cognito 会在创建或更新用户个人资料之前调用入站联合触发器。触发器从身份提供者那里接收原始属性，并可以在 Amazon Cognito 存储它们之前对其进行转换。对于新的联合用户和通过联合身份再次登录的现有用户，都会出现此流程。

![\[入站联邦 Lambda 触发流程\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/images/lambda-inbound-federation.png)


## 入站联邦 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-inbound-federation"></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 ]

```
{
    "version": "string",
    "triggerSource": "InboundFederation_ExternalProvider",
    "region": AWSRegion,
    "userPoolId": "string",
    "userName": "string",
    "callerContext": {
        "awsSdkVersion": "string",
        "clientId": "string"
    },
    "request": {
        "providerName": "string",
        "providerType": "string",
        "attributes": {
            "tokenResponse": {
                "access_token": "string",
                "token_type": "string",
                "expires_in": "string"
            },
            "idToken": {
                "sub": "string",
                "email": "string",
                "email_verified": "string"
            },
            "userInfo": {
                "email": "string",
                "given_name": "string",
                "family_name": "string"
            },
            "samlResponse": {
                "string": "string"
            }
        }
    },
    "response": {
        "userAttributesToMap": {
            "string": "string"
        }
    }
}
```

------

### 入站联盟请求参数
<a name="cognito-user-pools-lambda-trigger-syntax-inbound-federation-request"></a>

**提供者名称**  
外部身份提供商的名称。

**提供者类型**  
外部身份提供商的类型。有效值：`OIDC`、`SAML`、`Facebook`、`Google`、`SignInWithApple`、`LoginWithAmazon`。

**属性**  
处理前从身份提供者那里收到的原始属性。结构因提供商类型而异。

**属性。TokenResponse**  
OAuth 来自`/token`端点的令牌响应数据。仅适用于 OIDC 和社交服务提供商。包含`access_token``id_token`、`refresh_token`、`token_type`、`expires_in`、和`scope`。

**属性.idToken**  
经过解码和验证的 ID 令牌 JWT 声明。仅适用于 OIDC 和社交服务提供商。包含经过验证的用户身份信息，包括`sub`（唯一用户标识符）`email``name`、、`iss`（发行者）、`aud`（受众）、`exp`（到期）和`iat`（发布时间）。

**属性.userInfo**  
来自 UserInfo 端点的扩展用户配置文件信息。仅适用于 OIDC 和社交服务提供商。包含详细的配置文件属性`given_name`，例如、`family_name`、`picture``address`、和其他提供商特定的字段。如果 IdP 不支持 UserInfo 终端节点或端点调用失败，则可能为空。

**属性.samlResponse**  
SAML 断言属性。仅适用于 SAML 提供商。包含来自 SAML 响应的属性。

### 入站联盟响应参数
<a name="cognito-user-pools-lambda-trigger-syntax-inbound-federation-response"></a>

**userAttributesTo地图**  
要应用于用户配置文件的用户属性。

**重要**  
您必须在响应中包含要保留的所有用户属性，包括您未修改的属性。任何未包含在`userAttributesToMap`响应中的属性都将被删除且不会存储在用户配置文件中。这既适用于已修改的属性，也适用于未修改的属性。

**空响应行为**  
如果您`{}`为返回一个空对象`userAttributesToMap`，则身份提供者的所有原始属性都将保持不变。这相当于禁用操作，就像 Lambda 函数从未执行过一样。这与省略属性不同，后者会丢弃这些属性。

**提供商特定的属性**  
的结构`request.attributes`因而异`providerType`. OIDC 和社交提供者包括`tokenResponse``idToken`、和对象。`userInfo`SAML 提供程序仅包含`samlResponse`对象。

## 入站联盟示例：群组成员资格管理
<a name="aws-lambda-triggers-inbound-federation-example-groups"></a>

此示例说明如何将联合身份提供商组映射到 Amazon Cognito 用户池群组。此函数从联合响应中提取群组成员资格，并自动将用户添加到相应的 Amazon Cognito 群组，无需在身份验证后触发器。

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

```
exports.handler = async (event) => {
    const { providerType, attributes } = event.request;
    
    // Extract user attributes based on provider type
    let userAttributesFromIdp = {};
    if (providerType === 'SAML') {
        userAttributesFromIdp = attributes.samlResponse || {};
    } else {
        // For OIDC and Social providers, merge userInfo and idToken
        userAttributesFromIdp = {
            ...(attributes.userInfo || {}),
            ...(attributes.idToken || {})
        };
    }
    
    // Extract groups from federated response
    const federatedGroups = userAttributesFromIdp.groups?.split(',') || [];
    
    // Map federated groups to Cognito groups
    const groupMapping = {
        'Domain Admins': 'Administrators',
        'Engineering': 'Developers',
        'Sales': 'SalesTeam'
    };
    
    // Filter to only in-scope groups
    const mappedGroups = federatedGroups
        .map(group => groupMapping[group.trim()])
        .filter(group => group); // Remove undefined values
    
    // Pass through attributes with mapped groups as custom attribute
    const attributesToMap = {
        ...userAttributesFromIdp,
        'custom:user_groups': mappedGroups.join(',')
    };
    
    // Remove original groups attribute
    delete attributesToMap.groups;
    
    event.response.userAttributesToMap = attributesToMap;
    return event;
};
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
    "userPoolId": "us-east-1_XXXXXXXXX",
    "request": {
        "providerName": "CorporateAD",
        "providerType": "SAML",
        "attributes": {
            "samlResponse": {
                "email": "jane.smith@company.com",
                "given_name": "Jane",
                "family_name": "Smith",
                "groups": "Engineering,Domain Admins",
                "department": "Engineering"
            }
        }
    },
    "response": {
        "userAttributesToMap": {}
    }
}
```

------

## 入站联合示例：截断大型属性
<a name="aws-lambda-triggers-inbound-federation-example-truncate"></a>

此示例说明如何截断超过 Amazon Cognito 存储限制的属性值。此函数检查身份提供商提供的每个属性。如果属性值超过 2048 个字符，则会截断该值并添加省略号以表示截断。所有其他属性均保持不变。

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

```
exports.handler = async (event) => {
    const MAX_ATTRIBUTE_LENGTH = 2048;
    
    // Get the identity provider attributes based on provider type
    const { providerType, attributes } = event.request;
    let idpAttributes = {};
    
    if (providerType === 'SAML') {
        idpAttributes = attributes.samlResponse || {};
    } else {
        // For OIDC and Social providers, merge userInfo and idToken
        idpAttributes = {
            ...(attributes.userInfo || {}),
            ...(attributes.idToken || {})
        };
    }
    
    const userAttributes = {};
    
    // Process each attribute
    for (const [key, value] of Object.entries(idpAttributes)) {
        if (typeof value === 'string' && value.length > MAX_ATTRIBUTE_LENGTH) {
            // Truncate the value and add ellipsis
            userAttributes[key] = value.substring(0, MAX_ATTRIBUTE_LENGTH - 3) + '...';
            console.log(`Truncated attribute ${key} from ${value.length} to ${userAttributes[key].length} characters`);
        } else {
            // Keep the original value
            userAttributes[key] = value;
        }
    }
    
    // Return the modified attributes
    event.response.userAttributesToMap = userAttributes;
    return event;
};
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
    "version": "string",
    "triggerSource": "InboundFederation_ExternalProvider",
    "region": "us-east-1",
    "userPoolId": "us-east-1_XXXXXXXXX",
    "userName": "ExampleProvider_12345",
    "callerContext": {
        "awsSdkVersion": "string",
        "clientId": "string"
    },
    "request": {
        "providerName": "ExampleProvider",
        "providerType": "OIDC",
        "attributes": {
            "tokenResponse": {
                "access_token": "abcDE...",
                "token_type": "Bearer",
                "expires_in": "3600"
            },
            "idToken": {
                "sub": "12345",
                "email": "user@example.com"
            },
            "userInfo": {
                "email": "user@example.com",
                "given_name": "Example",
                "family_name": "User",
                "bio": "This is a very long biography that contains more than 2048 characters..."
            }
        }
    },
    "response": {
        "userAttributesToMap": {}
    }
}
```

------

## 入站联合示例：记录联合事件
<a name="aws-lambda-triggers-inbound-federation-example-logging"></a>

此示例说明如何记录联合身份验证事件以进行监控和调试。此示例函数捕获有关联合用户及其属性的详细信息，从而提供对身份验证过程的可见性。

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

```
exports.handler = async (event) => {
    const { providerName, providerType, attributes } = event.request;
    
    // Extract user attributes based on provider type
    let userAttributesFromIdp = {};
    if (providerType === 'SAML') {
        userAttributesFromIdp = attributes.samlResponse || {};
    } else {
        // For OIDC and Social providers, merge userInfo and idToken
        userAttributesFromIdp = {
            ...(attributes.userInfo || {}),
            ...(attributes.idToken || {})
        };
    }
    
    // Log federated authentication details
    console.log(JSON.stringify({
        timestamp: new Date().toISOString(),
        providerName,
        providerType,
        userEmail: userAttributesFromIdp.email,
        attributeCount: Object.keys(userAttributesFromIdp).length,
        attributes: userAttributesFromIdp
    }));
    
    // Pass through all attributes unchanged
    event.response.userAttributesToMap = userAttributesFromIdp;
    return event;
};
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
    "version": "string",
    "triggerSource": "InboundFederation_ExternalProvider",
    "region": "us-east-1",
    "userPoolId": "us-east-1_XXXXXXXXX",
    "userName": "CorporateAD_john.doe",
    "callerContext": {
        "awsSdkVersion": "string",
        "clientId": "string"
    },
    "request": {
        "providerName": "CorporateAD",
        "providerType": "SAML",
        "attributes": {
            "samlResponse": {
                "email": "john.doe@company.com",
                "given_name": "John",
                "family_name": "Doe",
                "department": "Engineering",
                "employee_id": "EMP12345"
            }
        }
    },
    "response": {
        "userAttributesToMap": {}
    }
}
```

------

预期的 CloudWatch 日志输出：

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

```
{
    "timestamp": "2025-01-14T21:17:40.153Z",
    "providerName": "CorporateAD",
    "providerType": "SAML",
    "userEmail": "john.doe@company.com",
    "attributeCount": 5,
    "attributes": {
        "email": "john.doe@company.com",
        "given_name": "John",
        "family_name": "Doe",
        "department": "Engineering",
        "employee_id": "EMP12345"
    }
}
```

------

# 自定义身份验证质询 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 };
```

------

# 令牌生成前 Lambda 触发器
<a name="user-pool-lambda-pre-token-generation"></a>

由于 Amazon Cognito 会在令牌生成之前调用此触发器，您可以自定义用户池令牌中的声明。使用版本 1 或 `V1_0` 令牌生成前触发器事件的**基本功能**，可以自定义身份（ID）令牌。在具有 Essentials 或 Plus 功能计划的用户池中，您可以使用访问令牌自定义生成版本二或`V2_0`触发事件，以及通过 machine-to-machine (M2M) 客户端凭证授予的访问令牌自定义来生成版本三或`V3_0`触发事件。

Amazon Cognito 将向您的函数发送 `V1_0` 请求，其中包含将写入 ID 令牌的数据。`V2_0` 或 `V3_0` 事件是包含将由 Amazon Cognito 写入身份和访问令牌的数据的单个请求。要自定义这两个令牌，您必须更新函数以使用触发器版本二或三，并在同一个响应中发送两个令牌的数据。

Amazon Cognito 将版本二的事件响应应用于来自用户身份验证的访问令牌，即由人类用户向您的用户池提供凭证的场景。版本三的事件响应则适用于来自用户身份验证和机器身份验证的访问令牌，即自动化系统使用应用程序客户端密钥授权访问令牌请求的场景。除了所生成访问令牌的使用场景不同之外，版本二和版本三的事件完全相同。

在 Amazon Cognito 向您的应用程序发布身份和访问令牌之前，此 Lambda 触发器可以添加、删除和修改这些令牌中的某些声明。要使用此功能，可以从 Amazon Cognito 用户池控制台关联 Lambda 函数或通过 AWS Command Line Interface （AWS CLI）更新用户池 `LambdaConfig`。

## 事件版本
<a name="user-pool-lambda-pre-token-generation-event-versions"></a>

您的用户池可以向您的 Lambda 函数提供不同版本的令牌生成前触发事件。`V1_0` 触发器提供用于修改 ID 令牌的参数。`V2_0` 或 `V3_0` 触发器为以下项提供参数。

1. `V1_0` 触发器的功能。

1. 能够自定义访问令牌。

1. 能够将复杂的数据类型传递给 ID 令牌和访问令牌声明值：
   + 字符串
   + 数字
   + 布尔值
   + 由字符串、数字、布尔值或它们的组合构成的数组
   + JSON

**注意**  
在 ID 令牌中，您可以将复杂对象填充到除了 `phone_number_verified`、`email_verified`、`updated_at` 和 `address` 之外的声明值。

默认情况下，用户池传送 `V1_0` 事件。要将用户池配置为发送 `V2_0` 事件，请在 Amazon Cognito 控制台中配置触发器时，在**基本功能 \$1 面向用户身份的访问令牌自定义设置**中选择**触发事件版本**。要生成 `V3_0` 事件，请选择****基本功能 \$1 面向用户和机器身份的访问令牌自定义设置****。您也可以在[UpdateUserPool ](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html)或 [CreateUserPool ](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html)API 请求的`LambdaVersion`[LambdaConfig](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html#CognitoUserPools-UpdateUserPool-request-LambdaConfig)参数中设置的值。事件版本一、二和三在**基础版**和**增值版**功能计划中均可用。版本三事件的 M2M 操作采用独立于每月活跃用户（MAU）计费公式的定价结构。有关更多信息，请参阅 [Amazon Cognito 定价](https://aws.amazon.com/cognito/pricing/)。

**注意**  
在 GMT 时间 2024 年 11 月 22 日 18:00 或之前已启用**高级安全功能**选项并持续保留在**精简版**功能层级的用户池，可使用令牌生成前触发器的事件版本一和版本二。此旧版层级中*未启用* 高级安全功能的用户池仅可使用事件版本一。版本三*仅* 在基础版和增值版中可用。

## 声明和作用域参考
<a name="user-pool-lambda-pre-token-generation-excluded-claims"></a>

Amazon Cognito 限制了您可以在访问令牌和身份令牌中添加、修改或隐藏的声明和作用域。下表描述了您的 Lambda 函数可以修改和不能修改的声明，以及影响声明存在或价值的触发器事件参数。


| 声明 | 默认令牌类型 | 是否可以添加？ | 是否可以修改？ | 是否可以隐藏？ | 事件参数 - 添加或修改 | 事件参数 - 隐藏 | 身份类型 | 事件版本 | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| 任何不在用户池令牌架构中的声明 | 无 | 支持 | 是 | 不适用 | claimsToAddOrOverride | claimsToSuppress | 用户、计算机[1](#cognito-pretoken-machine-ids-tier-note) | 全部 [2](#cognito-pretoken-id-access-versions-note) | 
| scope | 访问 | 支持 | 是 | 是 | scopesToAdd | scopesToSuppress | 用户、计算机[1](#cognito-pretoken-machine-ids-tier-note) | v2\$10, v3\$10 | 
| cognito:groups | ID、访问 | 支持 | 是 | 是 | groupsToOverride | claimsToSuppress | 用户 | 全部 [2](#cognito-pretoken-id-access-versions-note) | 
| cognito:preferred\$1role | ID | 支持 | 是 | 是 | preferredRole | claimsToSuppress[3](#cognito-pretoken-suppress-groups-note) | 用户 | 全部 | 
| cognito:roles | ID | 支持 | 是 | 是 | iamRolesToOverride | claimsToSuppress[3](#cognito-pretoken-suppress-groups-note) | 用户 | 全部 | 
| cognito:username | ID | 否 | 否 | 否 | 不适用 | 不适用 | 用户 | 不适用 | 
| 任何其他带有 cognito: 前缀的声明 | 无 | 否 | 否 | 否 | 不适用 | 不适用 | 不适用 | 不适用 | 
| username | 访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户 | v2\$10, v3\$10 | 
| sub | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户 | 不适用 | 
| 标准 OIDC 属性 | ID | 支持 | 是 | 是 | claimsToAddOrOverride | claimsToSuppress | 用户 | 全部 | 
| custom: 属性 | ID | 支持 | 是 | 是 | claimsToAddOrOverride | claimsToSuppress | 用户 | 全部 | 
| dev: 属性 | ID | 否 | 否 | 是 | 不适用 | claimsToSuppress | 用户 | 全部 | 
| identities | ID | 否 | 否 | 否 | 不适用 | 不适用 | 用户 | 不适用 | 
| aud[4](#cognito-pretoken-aud-note) | ID | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| client\$1id | 访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| event\$1id | 访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| device\$1key | 访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户 | 不适用 | 
| version | 访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| acr | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| amr | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| at\$1hash | ID | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| auth\$1time | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| azp | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| exp | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| iat | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| iss | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| jti | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| nbf | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| nonce | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| origin\$1jti | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 
| token\$1use | ID、访问 | 否 | 否 | 否 | 不适用 | 不适用 | 用户、计算机 | 不适用 | 

1 机器身份的访问令牌仅适用于 `v3_0` 的触发器输入事件。事件版本三仅在**基础版**和**增值版**功能层级中可用。**精简版**层级的用户池可以接收 `v1_0` 事件。启用高级安全功能的**精简版**用户池可以接收 `v1_0` 和 `v2_0` 事件。

2 将您的令牌生成前触发器配置为：使用事件版本 `v1_0` 仅处理 ID 令牌，使用 `v2_0` 处理 ID 令牌和访问令牌，使用 `v3_0` 处理 ID 令牌和访问令牌并提供机器身份相关功能。

3 要隐藏 `cognito:preferred_role` 和 `cognito:roles` 声明，请将 `cognito:groups` 添加到 `claimsToSuppress`。

 4 您可以向访问令牌添加 `aud` 声明，但其值必须与当前会话的应用程序客户端 ID 相匹配。您可以从 `event.callerContext.clientId` 获取请求事件中的客户端 ID。

## 自定义身份令牌
<a name="user-pool-lambda-pre-token-generation-idtoken"></a>

使用令牌生成前 Lambda 触发器的所有事件版本，您可以自定义来自用户池的身份（ID）令牌的内容。ID 令牌提供来自可信身份源的用户属性，用于登录 Web 或移动应用程序。有关 ID 令牌的更多信息，请参阅[了解身份（ID）令牌](amazon-cognito-user-pools-using-the-id-token.md)。

将令牌生成前 Lambda 触发器与 ID 令牌结合使用，可实现以下目的。
+ 在运行时更改您的用户从身份池中请求的 IAM 角色。
+ 从外部来源添加用户属性。
+ 添加或替换现有用户属性值。
+ 隐藏用户属性，否则这些属性由于用户获得的授权范围以及您授予应用程序客户端的属性读取权限，会传递给您的应用程序。

## 自定义访问令牌
<a name="user-pool-lambda-pre-token-generation-accesstoken"></a>

使用令牌生成前 Lambda 触发器的事件版本二和三，您可以自定义来自用户池的访问令牌的内容。访问令牌授权用户从受访问保护的资源（例如 Amazon Cognito 令牌授权的 API 操作和第三方）中检索信息。 APIs对于使用客户凭证授予的 machine-to-machine（M2M）授权，Amazon Cognito 仅在您的用户池配置为版本三 () 事件时才会调用令牌生成前触发器。`V3_0`有关访问令牌的更多信息，请参阅[了解访问令牌](amazon-cognito-user-pools-using-the-access-token.md)。

将令牌生成前 Lambda 触发器与访问令牌结合使用，可实现以下目的。
+ 在 `scope` 声明中添加或隐藏作用域。例如，您可以将作用域添加到由 Amazon Cognito 用户池 API 身份验证生成的访问令牌中，该身份验证仅分配作用域 `aws.cognito.signin.user.admin`。
+ 更改用户在用户池组中的成员资格。
+ 添加尚不存在于 Amazon Cognito 访问令牌中的声明。
+ 隐藏原本会传递到应用程序的声明。

要在用户池中支持访问自定义，必须将用户池配置为生成触发器请求的更新版本。请按照如下所示的过程更新用户池。

------
#### [ AWS 管理控制台 ]

**在令牌生成前 Lambda 触发器中支持访问令牌自定义**

1. 转到 [Amazon Cognito 控制台](https://console.aws.amazon.com/cognito/home)，然后选择**用户池**。

1. 从列表中选择一个现有用户池，或[创建一个用户池](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-as-user-directory.html)。

1. 选择**扩展**菜单并找到 **Lambda 触发器**。

1. 添加或编辑**令牌生成前触发器**。

1. 在**分配 Lambda 函数**下选择一个 Lambda 函数。

1. 在**基本功能 \$1 面向用户身份的访问令牌自定义设置**或**基本功能 \$1 面向用户和机器身份的访问令牌自定义设置**中，选择**触发事件版本**。此设置会更新 Amazon Cognito 发送给您的函数的请求参数，使该函数包含用于自定义访问令牌的字段。

------
#### [ User pools API ]

**在令牌生成前 Lambda 触发器中支持访问令牌自定义**

生成[CreateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html)或 [UpdateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html)API 请求。必须为所有您不想设置为默认值的参数指定一个值。有关更多信息，请参阅 [更新用户池和应用程序客户端配置](cognito-user-pool-updating.md)。

在请求的 `LambdaVersion` 参数中包含以下内容。`V2_0` 的值为 `LambdaVersion` 会使您的用户池为访问令牌添加相关参数并应用更改。`V3_0` 的值为 `LambdaVersion` 会生成与 `V2_0` 相同的事件，但会使您的用户池*同样* 向 M2M 访问令牌应用更改。要调用特定的函数版本，请使用以函数版本作为 `LambdaArn` 值的 Lambda 函数 ARN。

```
"PreTokenGenerationConfig": { 
   "LambdaArn": "arn:aws:lambda:us-west-2:123456789012:function:MyFunction",
   "LambdaVersion": "V3_0"
},
```

------

**machine-to-machine(M2M) 客户端凭证的客户端元数据**  
您可以在 M2M 请求中传递[客户端元数据](cognito-user-pools-working-with-lambda-triggers.md#working-with-lambda-trigger-client-metadata)。客户端元数据是来自用户或应用程序环境的附加信息，可影响[令牌生成前 Lambda 触发器](#user-pool-lambda-pre-token-generation)的结果。在使用用户委托人的身份验证操作中，您可以将客户端元数据传递给 [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html)API 请求正文中的令牌生成前触发器。[AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html)由于应用程序通过直接向 [令牌端点](token-endpoint.md) 发出请求来执行为 M2M 生成访问令牌的流程，因此它们的模型不同。在客户端凭证令牌请求的 POST 正文中，传递一个 `aws_client_metadata` 参数，其值为客户端元数据对象经 URL 编码（`x-www-form-urlencoded`）后的字符串。有关示例请求，请参阅[基本授权的客户端凭证POST 正文授权的客户端凭证](token-endpoint.md#exchanging-client-credentials-for-an-access-token-in-request-body)。以下是传递键值对 `{"environment": "dev", "language": "en-US"}` 的参数的示例。

```
aws_client_metadata=%7B%22environment%22%3A%20%22dev%22,%20%22language%22%3A%20%22en-US%22%7D
```

**更多资源**
+ [如何在 Amazon Cognito 用户池中自定义访问令牌](https://aws.amazon.com/blogs/security/how-to-customize-access-tokens-in-amazon-cognito-user-pools/)

**Topics**
+ [事件版本](#user-pool-lambda-pre-token-generation-event-versions)
+ [声明和作用域参考](#user-pool-lambda-pre-token-generation-excluded-claims)
+ [自定义身份令牌](#user-pool-lambda-pre-token-generation-idtoken)
+ [自定义访问令牌](#user-pool-lambda-pre-token-generation-accesstoken)
+ [令牌生成前 Lambda 触发器源](#user-pool-lambda-pre-token-generation-trigger-source)
+ [令牌生成前 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-pre-token-generation)
+ [令牌生成前触发器事件版本 2 示例：添加和隐藏声明、作用域及组](#aws-lambda-triggers-pre-token-generation-example-version-2-overview)
+ [令牌生成前事件版本 2 示例：添加包含复杂对象的声明](#aws-lambda-triggers-pre-token-generation-example-version-2-complex-objects)
+ [令牌生成前事件版本 1 示例：添加新声明并隐藏现有声明](#aws-lambda-triggers-pre-token-generation-version-1-add-claim)
+ [令牌生成前事件版本 1 示例：修改用户的组成员资格](#aws-lambda-triggers-pre-token-generation-version-1-change-group)

## 令牌生成前 Lambda 触发器源
<a name="user-pool-lambda-pre-token-generation-trigger-source"></a>


| triggerSource 值 | 事件 | 
| --- | --- | 
| TokenGeneration\$1HostedAuth | 通过 Amazon Cognito 托管登录的登录页进行身份验证时调用。 | 
| TokenGeneration\$1Authentication | 用户身份验证流完成之后调用。 | 
| TokenGeneration\$1NewPasswordChallenge | 管理员创建用户之后调用。当用户必须更改临时密码时调用此流。 | 
| TokenGeneration\$1ClientCredentials | 在 M2M 客户端凭证授予后调用。只有当您的事件版本为 V3\$10 时，您的用户池才会发送此事件。 | 
| TokenGeneration\$1AuthenticateDevice | 用户设备身份验证结束时调用。 | 
| TokenGeneration\$1RefreshTokens | 用户尝试刷新身份和令牌时调用。 | 

## 令牌生成前 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-pre-token-generation"></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)的组合。在向用户池添加令牌生成前 Lambda 触发器时，您可以选择触发器版本。此版本决定 Amazon Cognito 是否将请求以及用于自定义访问令牌的附加参数传递给您的 Lambda 函数。

------
#### [ Version one ]

版本一令牌可以在 ID 令牌中设置组成员资格、IAM 角色和新声明。组成员资格覆盖同样适用于访问令牌中的 `cognito:groups` 声明。

```
{
    "request": {
        "userAttributes": {"string": "string"},
        "groupConfiguration": {
                "groupsToOverride": [
                    "string",
                    "string"
                ],
                "iamRolesToOverride": [
                    "string",
                    "string"
                ],
                "preferredRole": "string"
        },
        "clientMetadata": {"string": "string"}
    },
    "response": {
        "claimsOverrideDetails": {
            "claimsToAddOrOverride": {"string": "string"},
            "claimsToSuppress": [
                "string",
                "string"
            ],
            "groupOverrideDetails": {
                "groupsToOverride": [
                    "string",
                    "string"
                ],
                "iamRolesToOverride": [
                    "string",
                    "string"
                ],
                "preferredRole": "string"
            }
        }
    }
}
```

------
#### [ Versions two and three ]

版本二和三请求事件添加了可自定义访问令牌的字段。用户池可将版本三事件的更改应用于机器身份的访问令牌。这些版本还添加了对响应对象中复杂 `claimsToOverride` 数据类型的支持。您的 Lambda 函数可以在 `claimsToOverride` 值中返回以下类型的数据：
+ 字符串
+ 数字
+ 布尔值
+ 由字符串、数字、布尔值或它们的组合构成的数组
+ JSON

```
{
    "request": {
        "userAttributes": {
            "string": "string"
        },
        "scopes": ["string", "string"],
        "groupConfiguration": {
            "groupsToOverride": ["string", "string"],
            "iamRolesToOverride": ["string", "string"],
            "preferredRole": "string"
        },
        "clientMetadata": {
            "string": "string"
        }
    },
    "response": {
        "claimsAndScopeOverrideDetails": {
            "idTokenGeneration": {
                "claimsToAddOrOverride": {
                    "string": [accepted datatype]
                },
                "claimsToSuppress": ["string", "string"]
            },
            "accessTokenGeneration": {
                "claimsToAddOrOverride": {
                    "string": [accepted datatype]
                },
                "claimsToSuppress": ["string", "string"],
                "scopesToAdd": ["string", "string"],
                "scopesToSuppress": ["string", "string"]
            },
            "groupOverrideDetails": {
                "groupsToOverride": ["string", "string"],
                "iamRolesToOverride": ["string", "string"],
                "preferredRole": "string"
            }
        }
    }
}
```

------

### 令牌生成前请求参数
<a name="cognito-user-pools-lambda-trigger-syntax-pre-token-generation-request"></a>


| Name | 说明 | 最低触发器事件版本 | 
| --- |--- |--- |
| userAttributes |  用户池中用户配置文件的属性。  | 1 | 
| groupConfiguration |  包含当前组配置的输入对象。对象包括 `groupsToOverride`、`iamRolesToOverride` 和 `preferredRole`。  | 1 | 
| groupsToOverride |  您的用户所属的[用户池组](cognito-user-pools-user-groups.md#cognito-user-pools-user-groups.title)。  | 1 | 
| iamRolesTo覆盖 |  您可以将用户池组与 AWS Identity and Access Management (IAM) 角色关联。此元素是您的用户所属组中的所有 IAM 角色的列表。  | 1 | 
| preferredRole |  您可以为用户池组设置一个[优先级](cognito-user-pools-user-groups.md#assigning-precedence-values-to-groups.title)。此元素包含 `groupsToOverride` 元素中具有最高优先级组中的 IAM 角色的名称。  | 1 | 
| 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 操作的数据。  | 1 | 
| 范围 |  访问令牌的作用域。访问令牌中的作用域是您的用户请求且您授权应用程序客户端发布的用户池标准作用域和自定义作用域。  | 2 | 

### 令牌生成前响应参数
<a name="cognito-user-pools-lambda-trigger-syntax-pre-token-generation-response"></a>


| Name | 说明 | 最低触发器事件版本 | 
| --- |--- |--- |
| claimsOverrideDetails | 用于存放 V1\$10 触发器事件中所有元素的容器。 | 1 | 
| claimsAndScopeOverrideDetails |  用于存放 `V2_0` 或 `V3_0` 触发器事件中所有元素的容器。  | 2 | 
| idTokenGeneration |  您要在用户的 ID 令牌中覆盖、添加或隐藏的声明。这是 ID 令牌自定义值的父元素，仅出现在版本 2 事件中，但子元素出现在版本 1 事件中。  | 2 | 
| accessTokenGeneration |  您要在用户的访问令牌中覆盖、添加或隐藏的声明和范围。这是访问令牌自定义值的父元素，仅出现在事件版本 2 及以上版本中。  | 2 | 
| claimsToAddOrOverride |  您要添加或修改的一个或多个声明及其值的映射。对于与组相关的声明，请改用 `groupOverrideDetails`。 在事件版本 2 及以上版本中，此元素同时出现在 `accessTokenGeneration` 和 `idTokenGeneration` 下。  | 1[*](#cognito-pretoken-complex-objects-note) | 
| claimsToSuppress |  您希望 Amazon Cognito 隐藏的声明列表。如果您的函数同时隐藏并替换了声明值，则 Amazon Cognito 会隐藏声明。 在事件版本 2 及以上版本中，此元素同时出现在 `accessTokenGeneration` 和 `idTokenGeneration` 下。  | 1 | 
| groupOverrideDetails |  包含当前组配置的输出对象。对象包括 `groupsToOverride`、`iamRolesToOverride` 和 `preferredRole`。 您的函数将 `groupOverrideDetails` 对象替换为您提供的对象。如果您在响应中提供空的或空对象，则 Amazon Cognito 将隐藏组。要保持现有组配置不变，请将请求的 `groupConfiguration` 对象的值复制到响应中的 `groupOverrideDetails` 对象。然后将其传回服务。 Amazon Cognito ID 令牌和访问令牌都包含 `cognito:groups` 声明。在访问令牌和 ID 令牌中，您的 `groupOverrideDetails` 对象将替换 `cognito:groups` 声明。组覆盖是版本 1 事件可以对访问令牌进行的唯一更改。  | 1 | 
| scopesToAdd |  您希望添加到用户访问令牌中的 `scope` 声明的作用域列表。不能添加包含一个或多个空格字符的作用域值。  | 2 | 
| scopesToSuppress |  您希望从用户访问令牌中的 `scope` 声明中移除的作用域列表。  | 2 | 

 \$1 版本一事件的响应对象可以返回字符串。版本二和三事件的响应对象可以返回[复杂对象](#user-pool-lambda-pre-token-generation-event-versions)。

## 令牌生成前触发器事件版本 2 示例：添加和隐藏声明、作用域及组
<a name="aws-lambda-triggers-pre-token-generation-example-version-2-overview"></a>

此示例对用户的令牌进行了以下修改。

1. 在 ID 令牌中将其 `family_name` 设置为 `Doe`。

1. 防止 `email` 和 `phone_number` 声明出现在 ID 令牌中。

1. 将其 ID 令牌 `cognito:roles` 声明设置为 `"arn:aws:iam::123456789012:role\/sns_callerA","arn:aws:iam::123456789012:role\/sns_callerC","arn:aws:iam::123456789012:role\/sns_callerB"`。

1. 将其 ID 令牌 `cognito:preferred_role` 声明设置为 `arn:aws:iam::123456789012:role/sns_caller`。

1. 将作用域 `openid`、`email` 和 `solar-system-data/asteroids.add` 添加到访问令牌中。

1. 隐藏访问令牌的作用域 `phone_number` 和 `aws.cognito.signin.user.admin`。删除 `phone_number` 可阻止从 `userInfo` 中检索用户的电话号码。删除 `aws.cognito.signin.user.admin` 可阻止用户通过 Amazon Cognito 用户池 API 请求读取和修改自己的个人资料。
**注意**  
只有当访问令牌中的剩余作用域包括 `openid` 和至少一个其他标准作用域时，从作用域中删除 `phone_number` 才会阻止检索用户的电话号码。有关更多信息，请参阅 [关于范围](cognito-user-pools-define-resource-servers.md#cognito-user-pools-define-resource-servers-about-scopes)。

1. 将其 ID 和访问令牌 `cognito:groups` 声明设置为 `"new-group-A","new-group-B","new-group-C"`。

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

```
export const handler = function(event, context) {
  event.response = {
    "claimsAndScopeOverrideDetails": {
      "idTokenGeneration": {
        "claimsToAddOrOverride": {
          "family_name": "Doe"
        },
        "claimsToSuppress": [
          "email",
          "phone_number"
        ]
      },
      "accessTokenGeneration": {
        "scopesToAdd": [
          "openid",
          "email",
          "solar-system-data/asteroids.add"
        ],
        "scopesToSuppress": [
          "phone_number",
          "aws.cognito.signin.user.admin"
        ]
      },
      "groupOverrideDetails": {
        "groupsToOverride": [
          "new-group-A",
          "new-group-B",
          "new-group-C"
        ],
        "iamRolesToOverride": [
          "arn:aws:iam::123456789012:role/new_roleA",
          "arn:aws:iam::123456789012:role/new_roleB",
          "arn:aws:iam::123456789012:role/new_roleC"
        ],
        "preferredRole": "arn:aws:iam::123456789012:role/new_role",
      }
    }
  };
  // Return to Amazon Cognito
  context.done(null, event);
};
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
    "version": "2",
    "triggerSource": "TokenGeneration_Authentication",
    "region": "us-east-1",
    "userPoolId": "us-east-1_EXAMPLE",
    "userName": "JaneDoe",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "1example23456789"
    },
    "request": {
        "userAttributes": {
            "sub": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
            "cognito:user_status": "CONFIRMED",
            "email_verified": "true",
            "phone_number_verified": "true",
            "phone_number": "+12065551212",
            "family_name": "Zoe",
            "email": "Jane.Doe@example.com"
        },
        "groupConfiguration": {
            "groupsToOverride": ["group-1", "group-2", "group-3"],
            "iamRolesToOverride": ["arn:aws:iam::123456789012:role/sns_caller1", "arn:aws:iam::123456789012:role/sns_caller2", "arn:aws:iam::123456789012:role/sns_caller3"],
            "preferredRole": ["arn:aws:iam::123456789012:role/sns_caller"]
        },
        "scopes": [
            "aws.cognito.signin.user.admin", "openid", "email", "phone"
        ]
    },
    "response": {
        "claimsAndScopeOverrideDetails": []
    }
}
```

------

## 令牌生成前事件版本 2 示例：添加包含复杂对象的声明
<a name="aws-lambda-triggers-pre-token-generation-example-version-2-complex-objects"></a>

此示例对用户的令牌进行了以下修改。

1. 将数字、字符串、布尔值和 JSON 类型的声明添加到 ID 令牌。这是版本二触发器事件可对 ID 令牌进行的唯一更改。

1. 将数字、字符串、布尔值和 JSON 类型的声明添加到访问令牌。

1. 将三个作用域添加到访问令牌。

1. 隐藏 ID 令牌和访问令牌中的 `email` 声明。

1. 隐藏访问令牌中的 `aws.cognito.signin.user.admin` 作用域。

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

```
export const handler = function(event, context) {

    var scopes = ["MyAPI.read", "MyAPI.write", "MyAPI.admin"]
    var claims = {}
    claims["aud"]= event.callerContext.clientId;
    claims["booleanTest"] = false;
    claims["longTest"] = 9223372036854775807;
    claims["exponentTest"] = 1.7976931348623157E308;
    claims["ArrayTest"] = ["test", 9223372036854775807, 1.7976931348623157E308, true];
    claims["longStringTest"] = "\{\
        \"first_json_block\": \{\
            \"key_A\": \"value_A\",\
            \"key_B\": \"value_B\"\
        \},\
        \"second_json_block\": \{\
            \"key_C\": \{\
                \"subkey_D\": [\
                    \"value_D\",\
                    \"value_E\"\
                ],\
                \"subkey_F\": \"value_F\"\
            \},\
            \"key_G\": \"value_G\"\
        \}\
    \}";
    claims["jsonTest"] = {
    	"first_json_block": {
    		"key_A": "value_A",
    		"key_B": "value_B"
    	},
    	"second_json_block": {
    		"key_C": {
    			"subkey_D": [
    				"value_D",
    				"value_E"
    			],
    			"subkey_F": "value_F"
    		},
    		"key_G": "value_G"
    	}
    };
    event.response = {
        "claimsAndScopeOverrideDetails": {
            "idTokenGeneration": {
                "claimsToAddOrOverride": claims,
                "claimsToSuppress": ["email"]
            },
            "accessTokenGeneration": {
                "claimsToAddOrOverride": claims,
                "claimsToSuppress": ["email"],
                "scopesToAdd": scopes,
                "scopesToSuppress": ["aws.cognito.signin.user.admin"]
            }
        }
    };
    console.info("EVENT response\n" + JSON.stringify(event, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2))
    console.info("EVENT response size\n" + JSON.stringify(event, (_, v) => typeof v === 'bigint' ? v.toString() : v).length)
    // Return to Amazon Cognito
    context.done(null, event);
};
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
    "version": "2",
    "triggerSource": "TokenGeneration_HostedAuth",
    "region": "us-west-2",
    "userPoolId": "us-west-2_EXAMPLE",
    "userName": "JaneDoe",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "1example23456789"
    },
    "request": {
        "userAttributes": {
            "sub": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
            "cognito:user_status": "CONFIRMED"
            "email_verified": "true",
            "phone_number_verified": "true",
            "phone_number": "+12065551212",
            "email": "Jane.Doe@example.com"
        },
        "groupConfiguration": {
            "groupsToOverride": ["group-1", "group-2", "group-3"],
            "iamRolesToOverride": ["arn:aws:iam::123456789012:role/sns_caller1"],
            "preferredRole": ["arn:aws:iam::123456789012:role/sns_caller1"]
        },
        "scopes": [
            "aws.cognito.signin.user.admin",
            "phone",
            "openid",
            "profile",
            "email"
        ]
    },
    "response": {
        "claimsAndScopeOverrideDetails": []
    }
}
```

------

## 令牌生成前事件版本 1 示例：添加新声明并隐藏现有声明
<a name="aws-lambda-triggers-pre-token-generation-version-1-add-claim"></a>

此示例将版本 1 触发器事件与令牌生成前 Lambda 函数结合使用，以添加新声明并隐藏现有声明。

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

```
const handler = async (event) => {
  event.response = {
    claimsOverrideDetails: {
      claimsToAddOrOverride: {
        my_first_attribute: "first_value",
        my_second_attribute: "second_value",
      },
      claimsToSuppress: ["email"],
    },
  };

  return event;
};

export { handler };
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的测试事件：由于该代码示例不处理任何请求参数，因此您可以使用带有空请求的测试事件。有关常见请求参数的更多信息，请参阅[用户池 Lambda 触发器事件](cognito-user-pools-working-with-lambda-triggers.md#cognito-user-pools-lambda-trigger-event-parameter-shared)。

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

```
{
  "request": {},
  "response": {}
}
```

------

## 令牌生成前事件版本 1 示例：修改用户的组成员资格
<a name="aws-lambda-triggers-pre-token-generation-version-1-change-group"></a>

此示例将版本 1 触发器事件与令牌生成前 Lambda 函数结合使用，以修改用户的组成员资格。

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

```
const handler = async (event) => {
  event.response = {
    claimsOverrideDetails: {
      groupOverrideDetails: {
        groupsToOverride: ["group-A", "group-B", "group-C"],
        iamRolesToOverride: [
          "arn:aws:iam::XXXXXXXXXXXX:role/sns_callerA",
          "arn:aws:iam::XXXXXXXXX:role/sns_callerB",
          "arn:aws:iam::XXXXXXXXXX:role/sns_callerC",
        ],
        preferredRole: "arn:aws:iam::XXXXXXXXXXX:role/sns_caller",
      },
    },
  };

  return event;
};

export { handler };
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
  "request": {},
  "response": {}
}
```

------

# 迁移用户 Lambda 触发器
<a name="user-pool-lambda-migrate-user"></a>

如果用户在使用密码登录时或在使用忘记密码流程时不在用户池中，Amazon Cognito 会调用此触发器。Lambda 函数成功返回后，Amazon Cognito 将在用户池中创建用户。有关利用用户迁移 Lambda 触发器进行身份验证流程的详细信息，请参阅[利用用户迁移 Lambda 触发器导入用户](cognito-user-pools-import-using-lambda.md)。

要在用户登录时或在忘记密码流程中，将用户从您的现有用户目录迁移到 Amazon Cognito 用户池，请使用此 Lambda 触发器。

**Topics**
+ [迁移用户 Lambda 触发器源](#user-pool-lambda-migrate-user-trigger-source)
+ [迁移用户 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-user-migration)
+ [示例：使用现有密码迁移用户](#aws-lambda-triggers-user-migration-example-1)

## 迁移用户 Lambda 触发器源
<a name="user-pool-lambda-migrate-user-trigger-source"></a>


| triggerSource 值 | 事件 | 
| --- | --- | 
| UserMigration\$1Authentication[1](#cognito-migrate-user-passwordless-note) | 登录时的用户迁移。 | 
| UserMigration\$1ForgotPassword | 在忘记密码流程中迁移用户。 | 

1 当用户使用[无密码登录](amazon-cognito-user-pools-authentication-flow-methods.md#amazon-cognito-user-pools-authentication-flow-methods-passwordless)进行身份验证时，Amazon Cognito 不会调用此触发器。

## 迁移用户 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-user-migration"></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 ]

```
{
    "userName": "string",
    "request": {
        "password": "string",
        "validationData": {
            "string": "string",
            . . .
        },
        "clientMetadata": {
            "string": "string",
      	. . .
        }
    },
    "response": {
        "userAttributes": {
            "string": "string",
            . . .
        },
        "finalUserStatus": "string",
        "messageAction": "string",
        "desiredDeliveryMediums": [ "string", . . .],
        "forceAliasCreation": boolean,
        "enableSMSMFA": boolean
    }
}
```

------

### 迁移用户请求参数
<a name="cognito-user-pools-lambda-trigger-syntax-user-migration-request"></a>

**userName**  
用户在登录时输入的用户名。

**password**  
用户在登录时输入的密码。Amazon Cognito 不会在由忘记密码流程发起的请求中发送此值。

**validationData**  
一个或多个键/值对，包含用户的登录请求中的验证数据。要将此数据传递给您的 Lambda 函数，您可以使用[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)API 操作中的 ClientMetadata 参数。

**clientMetadata**  
一个或多个键/值对，您可以将其作为自定义输入内容提供给迁移用户触发器的 Lambda 函数。要将此数据传递给您的 Lambda 函数，您可以使用[AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html)和 [ForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ForgotPassword.html)API 操作中的 ClientMetadata 参数。

### 迁移用户响应参数
<a name="cognito-user-pools-lambda-trigger-syntax-user-migration-response"></a>

**userAttributes**  
该字段为必填。  
该字段必须包含一个或多个名称/值对，Amazon Cognito 将其存储在用户池的用户配置文件中并用作用户属性。您可以同时包括标准的和自定义的用户属性。自定义属性需要使用 `custom:` 前缀，以便与标准属性区分开来。有关更多信息，请参阅[自定义属性](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-custom-attributes.html)。  
要在忘记密码流程中重置密码，用户必须拥有经过验证的电子邮件地址或经过验证的电话号码。Amazon Cognito 将包含重置密码代码的消息发送到用户属性中的电子邮件地址或电话号码。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/user-pool-lambda-migrate-user.html)

**finalUserStatus**  
您可以将此参数设置为 `CONFIRMED` 以自动确认用户，这样他们就可以使用之前的密码登录。当您将用户设置为 `CONFIRMED` 时，他们无需执行额外的操作即可登录。如果您未将此属性设置为 `CONFIRMED`，则它会设置为 `RESET_REQUIRED`。  
若 `finalUserStatus` 设置为 `RESET_REQUIRED`，则意味着用户在迁移之后，必须在登录时立即更改密码，并且您的客户端应用程序必须在身份验证中处理 `PasswordResetRequiredException`。  
使用 Lambda 触发器迁移期间，Amazon Cognito 不强制执行您为用户池配置的密码强度策略。如果密码不符合您配置的密码策略，Amazon Cognito 仍会接受密码，以便它继续迁移用户。要强制实施密码强度策略并拒绝不符合策略的密码，请验证代码中的密码强度。然后，如果密码不符合政策，则设置 finalUserStatus 为`RESET_REQUIRED`。

**messageAction**  
您可以将此参数设置为 `SUPPRESS`，以拒绝发送 Amazon Cognito 通常会向新用户发送的欢迎消息。如果您的函数未返回此参数，Amazon Cognito 会发送欢迎消息。

**desiredDeliveryMediums**  
您可以将此参数设置为 `EMAIL` 以通过电子邮件发送欢迎消息，或者设置为 `SMS` 以通过 SMS 发送欢迎消息。如果您的函数未返回此参数，Amazon Cognito 通过 SMS 发送欢迎消息。

**forceAliasCreation**  
如果您将此参数设置为，`TRUE`并且 UserAttributes 参数中的电话号码或电子邮件地址已作为其他用户的别名存在，则 API 调用会将该别名从以前的用户迁移到新创建的用户。以前的用户无法再使用该别名登录。  
如果您将此参数设置为 `FALSE` 而且别名存在，Amazon Cognito 不会迁移用户，并向客户端应用程序返回错误。  
如果您不返回此参数，Amazon Cognito 会假定其值为“false”。

**enableSMSMFA**  
将此参数设置为 `true`，要求迁移的用户完成 SMS 短信多重身份验证 (MFA) 才能登录。您的用户池必须启用 MFA。请求参数中的用户属性必须包含电话号码，否则该用户的迁移将失败。

## 示例：使用现有密码迁移用户
<a name="aws-lambda-triggers-user-migration-example-1"></a>

此示例 Lambda 函数使用现有密码迁移用户，并隐藏 Amazon Cognito 发送的欢迎消息。

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

```
exports.handler = (event, context, callback) => {
  var user;

  if (event.triggerSource == "UserMigration_Authentication") {
    // authenticate the user with your existing user directory service
    user = authenticateUser(event.userName, event.request.password);
    if (user) {
      event.response.userAttributes = {
        email: user.emailAddress,
        email_verified: "true",
      };
      event.response.finalUserStatus = "CONFIRMED";
      event.response.messageAction = "SUPPRESS";
      context.succeed(event);
    } else {
      // Return error to Amazon Cognito
      callback("Bad password");
    }
  } else if (event.triggerSource == "UserMigration_ForgotPassword") {
    // Lookup the user in your existing user directory service
    user = lookupUser(event.userName);
    if (user) {
      event.response.userAttributes = {
        email: user.emailAddress,
        // required to enable password-reset code to be sent to user
        email_verified: "true",
      };
      event.response.messageAction = "SUPPRESS";
      context.succeed(event);
    } else {
      // Return error to Amazon Cognito
      callback("Bad password");
    }
  } else {
    // Return error to Amazon Cognito
    callback("Bad triggerSource " + event.triggerSource);
  }
};
```

------

# 自定义消息 Lambda 触发器
<a name="user-pool-lambda-custom-message"></a>

如果您对要发送给用户的电子邮件和短信设置了外部标准，或者您想在运行时将自己的逻辑应用于用户消息的格式化，请向您的用户池中添加自定义消息触发器。自定义消息 Lambda 会在您的用户池发送所有电子邮件和短信消息的内容之前先接收这些内容。然后，您的 Lambda 函数就有机会修改消息内容和主题。

Amazon Cognito 在发送电子邮件或电话验证消息或多重验证 (MFA) 代码前调用此触发器。您可以使用自定义消息触发器动态自定义消息。

该请求包括 `codeParameter`。这是一个字符串，用作 Amazon Cognito 传递给用户的代码的占位符。将 `codeParameter` 字符串插入消息正文中用于显示验证码的位置。Amazon Cognito 在收到此响应后，Amazon Cognito 将 `codeParameter` 字符串替换为实际验证码。

**注意**  
使用 `CustomMessage_AdminCreateUser` 触发器源时，自定义消息 Lambda 函数的输入事件将包含用户名和验证码。由于管理员创建的用户必须同时收到其用户名和验证码，因此来自您的函数的响应必须同时包含用户名和验证码的占位符变量。消息的占位符是 `request.usernameParameter` 和 `request.codeParameter` 的值。这些值通常是 `{username}` 和 `{####}`；作为最佳实践，请引用输入值，而不是对变量名称进行硬编码。

**Topics**
+ [自定义消息 Lambda 触发器源](#cognito-user-pools-lambda-trigger-syntax-custom-message-trigger-source)
+ [自定义消息 Lambda 触发器参数](#cognito-user-pools-lambda-trigger-syntax-custom-message)
+ [用于注册的自定义消息示例](#aws-lambda-triggers-custom-message-example)
+ [管理员创建用户的自定义消息示例](#aws-lambda-triggers-custom-message-admin-example)

## 自定义消息 Lambda 触发器源
<a name="cognito-user-pools-lambda-trigger-syntax-custom-message-trigger-source"></a>


| triggerSource 值 | 事件 | 
| --- | --- | 
| CustomMessage\$1SignUp | 自定义消息 – 在注册后发送确认码。 | 
| CustomMessage\$1AdminCreateUser | 自定义消息 – 向新用户发送临时密码。 | 
| CustomMessage\$1ResendCode | 自定义消息 – 向现有用户重新发送确认码。 | 
| CustomMessage\$1ForgotPassword | 自定义消息 – 针对“忘记密码”请求发送确认码。 | 
| CustomMessage\$1UpdateUserAttribute | 自定义消息 – 当用户的电子邮件或电话号码发生更改时，此触发器自动向用户发送验证码。不可用于其他属性。 | 
| CustomMessage\$1VerifyUserAttribute | 自定义消息 – 当用户针对新的电子邮件或电话号码手动请求验证码时，此触发器向用户发送验证码。 | 
| CustomMessage\$1Authentication | 自定义消息 – 在身份验证过程中发送 MFA 代码。 | 

## 自定义消息 Lambda 触发器参数
<a name="cognito-user-pools-lambda-trigger-syntax-custom-message"></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",
            . . .
        }
        "codeParameter": "####",
        "usernameParameter": "string",
        "clientMetadata": {
            "string": "string",
            . . .
        }
    },
    "response": {
        "smsMessage": "string",
        "emailMessage": "string",
        "emailSubject": "string"
    }
}
```

------

### 自定义消息请求参数
<a name="cognito-user-pools-lambda-trigger-syntax-custom-message-request"></a>

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

**codeParameter**  
一个字符串，用作自定义消息中验证码的占位符。

**usernameParameter**  
用户名。Amazon Cognito 在管理员创建的用户发出的请求中包含此参数。

**clientMetadata**  
一个或多个键值对，您可以将其作为自定义输入内容提供给为自定义消息触发器指定的 Lambda 函数。调用自定义消息函数的请求不包括在 [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html)API 操作中的 ClientMetadata 参数中[AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html)传递的数据。要将此数据传递给您的 Lambda 函数，您可以在以下 API 操作中使用 ClientMetadata 参数：  
+  [AdminResetUserPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminResetUserPassword.html) 
+  [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) 
+  [AdminUpdateUserAttributes](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminUpdateUserAttributes.html)
+  [ForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ForgotPassword.html)
+  [GetUserAttributeVerificationCode](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_GetUserAttributeVerificationCode.html)
+  [ResendConfirmationCode](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ResendConfirmationCode.html)
+  [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html)
+  [UpdateUserAttributes](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserAttributes.html)

### 自定义消息响应参数
<a name="cognito-user-pools-lambda-trigger-syntax-custom-message-response"></a>

在响应中，指定要在发送给用户的消息中使用的自定义文本。有关 Amazon Cognito 适用于这些参数的字符串限制，请参阅。[MessageTemplateType](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_MessageTemplateType.html)

**smsMessage**  
要发送给用户的自定义 SMS 消息。必须包含您在请求中收到的 `codeParameter` 值。

**emailMessage**  
发送给用户的自定义电子邮件。您可以在 `emailMessage` 参数中使用 HTML 格式。必须包含您在请求中收到的 `codeParameter` 值作为变量 `{####}`。只有在用户池的 `EmailSendingAccount` 属性为 `DEVELOPER` 时，Amazon Cognito 才可以使用`emailMessage` 参数。如果用户池的 `EmailSendingAccount` 属性不是 `DEVELOPER` 且返回了 `emailMessage` 参数，Amazon Cognito 会生成 400 错误代码 `com.amazonaws.cognito.identity.idp.model.InvalidLambdaResponseException`。当您选择使用 Amazon Simple Email Service (Amazon SES) 发送电子邮件时，用户池的 `EmailSendingAccount` 属性为 `DEVELOPER`。否则，该值为 `COGNITO_DEFAULT`。

**emailSubject**  
自定义消息的主题行。只有当用户池的 EmailSendingAccount属性为时，您才能使用该`emailSubject`参数`DEVELOPER`。如果用户池的 `EmailSendingAccount` 属性不是 `DEVELOPER` 且 Amazon Cognito 返回了 `emailSubject` 参数，Amazon Cognito 会生成 400 错误代码 `com.amazonaws.cognito.identity.idp.model.InvalidLambdaResponseException`。当您选择使用 Amazon Simple Email Service (Amazon SES) 发送电子邮件时，用户池的 `EmailSendingAccount` 属性为 `DEVELOPER`。否则，该值为 `COGNITO_DEFAULT`。

## 用于注册的自定义消息示例
<a name="aws-lambda-triggers-custom-message-example"></a>

当服务要求应用程序向用户发送验证码时，此示例 Lambda 函数自定义电子邮件或 SMS 消息。

Amazon Cognito 可以在多个事件中调用 Lambda 触发器：注册后、重新发送验证码时、恢复忘记的密码时或验证用户属性时。响应包括电子邮件和 SMS 消息。该消息必须包含代码参数 `"####"`。此参数是用户收到的验证码的占位符。

电子邮件的最大长度为 20000 个 UTF-8 字符。此长度包括验证码。您可以在这些电子邮件中使用 HTML 标签。

SMS 消息的最大长度为 140 个 UTF-8 个字符。此长度包括验证码。

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

```
const handler = async (event) => {
  if (event.triggerSource === "CustomMessage_SignUp") {
    const message = `Thank you for signing up. Your confirmation code is ${event.request.codeParameter}.`;
    event.response.smsMessage = message;
    event.response.emailMessage = message;
    event.response.emailSubject = "Welcome to the service.";
  }
  return event;
};

export { handler };
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
	"version": "1",
	"region": "us-west-2",
	"userPoolId": "us-west-2_EXAMPLE",
	"userName": "test-user",
	"callerContext": {
		"awsSdkVersion": "aws-sdk-unknown-unknown",
		"clientId": "1example23456789"
	},
	"triggerSource": "CustomMessage_SignUp",
	"request": {
		"userAttributes": {
			"sub": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
			"cognito:user_status": "CONFIRMED",
			"email_verified": "true",
			"phone_number_verified": "true",
			"phone_number": "+12065551212",
			"email": "test-user@example.com"
		},
		"codeParameter": "{####}",
		"linkParameter": "{##Click Here##}",
		"usernameParameter": "None"
	},
	"response": {
		"smsMessage": "None",
		"emailMessage": "None",
		"emailSubject": "None"
	}
}
```

------

## 管理员创建用户的自定义消息示例
<a name="aws-lambda-triggers-custom-message-admin-example"></a>

Amazon Cognito 向此示例自定义消息 Lambda 函数发送的请求的 `triggerSource` 值为 `CustomMessage_AdminCreateUser`，并且拥有用户名和临时密码。该函数根据请求中的临时密码填入 `${event.request.codeParameter}`，并根据请求中的用户名填入 `${event.request.usernameParameter}`。

您的自定义消息必须将 `codeParameter` 和 `usernameParameter` 的值插入响应对象中的 `smsMessage` 和 `emailMessage`。在此示例中，该函数将相同的消息写入响应字段 `event.response.smsMessage` 和 `event.response.emailMessage`。

电子邮件的最大长度为 20000 个 UTF-8 字符。此长度包括验证码。您可以在这些电子邮件中使用 HTML 标签。SMS 消息的最大长度为 140 个 UTF-8 个字符。此长度包括验证码。

响应包括电子邮件和 SMS 消息。

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

```
const handler = async (event) => {
  if (event.triggerSource === "CustomMessage_AdminCreateUser") {
    const message = `Welcome to the service. Your user name is ${event.request.usernameParameter}. Your temporary password is ${event.request.codeParameter}`;
    event.response.smsMessage = message;
    event.response.emailMessage = message;
    event.response.emailSubject = "Welcome to the service";
  }
  return event;
};

export { handler };
```

------

Amazon Cognito 将事件信息传递给 Lambda 函数。随后，该函数将相同事件对象随同响应中的任何更改返回给 Amazon Cognito。在 Lambda 控制台中，您可以设置一个测试事件，该事件包含与您的 Lambda 触发器相关的数据。以下是此代码示例的一个测试事件：

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

```
{
  "version": 1,
  "triggerSource": "CustomMessage_AdminCreateUser",
  "region": "<region>",
  "userPoolId": "<userPoolId>",
  "userName": "<userName>",
  "callerContext": {
      "awsSdk": "<calling aws sdk with version>",
      "clientId": "<apps client id>",
      ...
  },
  "request": {
      "userAttributes": {
          "phone_number_verified": false,
          "email_verified": true,
           ...
      },
      "codeParameter": "####",
      "usernameParameter": "username"
  },
  "response": {
      "smsMessage": "<custom message to be sent in the message with code parameter and username parameter>"
      "emailMessage": "<custom message to be sent in the message with code parameter and username parameter>"
      "emailSubject": "<custom email subject>"
  }
}
```

------

# 自定义发件人 Lambda 触发器
<a name="user-pool-lambda-custom-sender-triggers"></a>

Lambda 触发器 `CustomEmailSender` 和 `CustomSMSSender` 支持在用户池中使用第三方电子邮件和短信通知。您可以选择 SMS 和电子邮件提供商，通过 Lambda 函数代码向用户发送通知。当 Amazon Cognito 向用户发送邀请、MFA 代码、确认码、验证码或临时密码时，这些事件会激活您配置的 Lambda 函数。Amazon Cognito 将代码和临时密码（密钥）发送到您激活的 Lambda 函数。Amazon Cognito 使用 AWS KMS 客户管理的密钥对这些机密进行加密，然后. AWS Encryption SDK AWS Encryption SDK 是一个客户端加密库，可帮助您加密和解密通用数据。

**[CustomEmailSender](user-pool-lambda-custom-email-sender.md)**  
Amazon Cognito 调用此触发器向用户发送电子邮件通知。

**[自定义SMSSender](user-pool-lambda-custom-sms-sender.md)**  
Amazon Cognito 调用此触发器向用户发送 SMS 通知。

## 加密概念
<a name="user-pool-lambda-custom-sender-triggers-resources"></a>

Amazon Cognito 不会在发送给自定义发件人触发器的事件中以明文形式发送用户的代码。Lambda 函数必须解密事件中的代码。以下概念是加密架构，您的函数必须使用该架构来获取可以传递给用户的代码。

**AWS KMS**  
AWS KMS 是一项用于创建和控制 AWS KMS 密钥的托管服务。这些密钥加密您的数据。有关更多信息，请参阅[什么是 AWS Key Management Service？](/kms/latest/developerguide/overview.html)。

**KMS 密钥**  
KMS 密钥是加密密钥的逻辑表示形式。KMS 密钥包含元数据，如密钥 ID、创建日期、描述和密钥状态。KMS 密钥还包含用于加密和解密数据的密钥材料。有关更多信息，请参阅 [AWS KMS 密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#kms_keys)。

**对称 KMS 密钥**  
对称 KMS 密钥是一个 256 位加密密钥，它不会退出 AWS KMS 而不加密。要使用对称 KMS 密钥，必须调用 AWS KMS。Amazon Cognito 使用对称密钥。加密和解密使用同一密钥。有关更多信息，请参阅[对称 KMS 密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#symmetric-cmks)。

## 有关自定义发件人 Lambda 触发器的需知信息
<a name="user-pool-lambda-custom-sender-triggers-things-to-know"></a>
+ 要配置用户池以使用这些 Lambda 触发器，您可以使用 AWS CLI 或开发工具包。无法从 Amazon Cognito 控制台进行这些配置。

  `UpdateUserPool` 操作可设置 Lambda 配置。对此操作的请求需要包含用户池的所有参数*和* 您要更改的参数。如果您没有提供所有相关参数，Amazon Cognito 会将任何缺失参数的值设置为其原定设置。如下面的 AWS CLI 示例所示，包括您要添加到用户池或保留在用户池中的所有 Lambda 函数的条目。有关更多信息，请参阅 [更新用户池和应用程序客户端配置](cognito-user-pool-updating.md)。

  ```
      #Send this parameter in an 'aws cognito-idp update-user-pool' CLI command, including any existing 
      #user pool configurations. This snippet also includes a pre sign-up trigger for syntax reference. The pre sign-up trigger
      #doesn't have a role in custom sender triggers.
                
        --lambda-config "PreSignUp=lambda-arn, \
                         CustomSMSSender={LambdaVersion=V1_0,LambdaArn=lambda-arn}, \
                         CustomEmailSender={LambdaVersion=V1_0,LambdaArn=lambda-arn}, \
                         KMSKeyID=key-id"
  ```

  对于使用 `UpdateUserPool` 的 JSON 正文的请求，以下 `LambdaConfig` 代码段可分配自定义的短信和电子邮件发件人函数。

  ```
  "LambdaConfig": {
     "KMSKeyID": "arn:aws:kms:us-east-1:111122223333:key/a6c4f8e2-0c45-47db-925f-87854bc9e357",
     "CustomEmailSender": {
        "LambdaArn": "arn:aws:lambda:us-east-1:111122223333:function:MyFunction",
        "LambdaVersion": "V1_0"
     },
     "CustomSMSSender": {
        "LambdaArn": "arn:aws:lambda:us-east-1:111122223333:function:MyFunction",
        "LambdaVersion": "V1_0"
     }
  ```
+ 要使用`update-user-pool` AWS CLI 命令移除自定义发送器 Lambda 触发器，请省略`CustomSMSSender`或`CustomEmailSender`参数`--lambda-config`，并包含您要在用户池中使用的所有其他触发器。

  要使用 `UpdateUserPool` API 请求删除自定义发件人 Lambda 触发器，请在包含其余用户池配置的请求正文中省略 `CustomSMSSender` 或 `CustomEmailSender` 参数。
+ Amazon Cognito HTML 会转义用户临时密码中的保留字符，例如 `<`（`&lt;`）和 `&gt;`（`>`）等。这些字符可能出现在 Amazon Cognito 发送到您的自定义电子邮件发件人函数的临时密码中，但不会出现在临时验证码中。要发送临时密码，您的 Lambda 函数在解密密码之后必须取消对这些字符的转义，然后再将消息发送给您的用户。

## 激活自定义发件人 Lambda 触发器
<a name="enable-custom-sender-lambda-trigger"></a>

要使用自定义逻辑为您的用户池发送短信或电子邮件消息，请设置自定义发件人触发器。以下步骤会将自定义短信触发器和/或自定义电子邮件触发器分配给您的用户池。添加自定义发件人触发器后，Amazon Cognito 始终向您的 Lambda 函数发送用户属性（包括电话号码）和一次性代码，而不是采用发送短信或电子邮件消息的默认行为。

1. 在 AWS Key Management Service (AWS KMS) 中创建[对称加密密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#symmetric-cmks)。Amazon Cognito 生成密钥（临时密码、验证码、身份验证一次性密码和确认码），然后使用此 KMS 密钥通过 [AWS Encryption SDK](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html) 对这些密钥进行加密。然后，您可以 AWS Encryption SDK 在 Lambda 函数中使用解密密密钥并将其以明文形式发送给用户。

1. 创建或更新您的用户池的 IAM 主体会针对 Amazon Cognito 用于加密代码的 KMS 密钥创建一次性授权。请为该主体授予对您的 KMS 密钥的 `CreateGrant` 权限。要使本示例中的 KMS 密钥策略生效，更新用户池的管理员必须以 IAM 角色 `arn:aws:iam::111222333444:role/my-example-administrator-role` 的代入角色会话身份登录。

   请将以下基于资源的策略（已针对您的环境进行修改）应用于您的 KMS 密钥。

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

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
       {
           "Effect": "Allow",
           "Principal": {
               "AWS": "arn:aws:iam::111122223333:role/my-example-administrator-role"
           },
           "Action": "kms:CreateGrant",
           "Resource": "arn:aws:kms:us-west-2:111122223333:key/1example-2222-3333-4444-999example",
           "Condition": {
               "StringEquals": {
                  "kms:EncryptionContext:userpool-id": "us-west-2_EXAMPLE"
               }
           }
       },
       {
           "Sid": "Allow Lambda to decrypt",
           "Effect": "Allow",
           "Principal": {
               "AWS": "arn:aws:iam::111122223333:role/my-lambda-function-role"
           },
           "Action": "kms:Decrypt",
           "Resource": "*"
       }]
   }
   ```

------

1. 为自定义发件人触发器创建 Lambda 函数。Amazon Cognito 使用 [AWS Encryption SDK ](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html)加密密钥、临时密码和授权用户 API 请求的代码。

   1. 分配一个 [Lambda 执行角色](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html)，该角色至少具有针对您的 KMS 密钥的 `kms:Decrypt` 权限。

   1. 编写 Lambda 函数代码以发送消息。您函数的输入事件将包含一个密钥。在您的函数中，使用解密密密钥 AWS Encryption SDK 并处理所有相关的元数据。然后将代码、您自己的自定义消息和目标电话号码发送到传送消息的自定义 API。

   1. 将 AWS Encryption SDK 添加到您的 Lambda 函数中。有关更多信息，请参阅 [AWS Encryption SDK 编程语言](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/programming-languages.html)。要更新 Lambda 包，请完成以下步骤：

      1. 在 AWS 管理控制台中将您的 Lambda 函数作为.zip 文件导出。

      1. 打开您的函数并添加 AWS Encryption SDK. 有关更多信息和下载链接，请参阅 *AWS Encryption SDK Developer Guide*（《Crypto SDK 开发人员指南》）中的 [AWS Encryption SDK 编程语言](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/programming-languages.html)。

      1. 压缩您的函数及 SDK 依赖项，然后将函数上传到 Lambda。有关更多信息，请参阅《AWS Lambda 开发人员指南》**中的[将 Lambda 函数部署为 .zip 文件归档](https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-zip.html#configuration-function-create)。

1. 授予 Amazon Cognito 服务主体 `cognito-idp.amazonaws.com` 访问权限，以调用 Lambda 函数。

   以下 AWS CLI 命令授予 Amazon Cognito 调用您的 Lambda 函数的权限：

   ```
   aws lambda add-permission --function-name lambda_arn --statement-id "CognitoLambdaInvokeAccess" --action lambda:InvokeFunction --principal cognito-idp.amazonaws.com
   ```

1. 使用添加自定义发送器 Lambda 触发器的`LambdaConfig`参数生成 [UpdateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html)API 请求。此类触发器无法通过 Amazon Cognito 控制台添加。自定义发件人触发器要求 `LambdaConfig` 参数中必须包含 `KMSKeyID` 以及 `CustomSMSSender` 或 `CustomEmailSender`（或两者同时包含）。

# 自定义电子邮件发件人 Lambda 触发器
<a name="user-pool-lambda-custom-email-sender"></a>

当您为用户池分配自定义电子邮件发件人触发器时，如果用户事件要求 Amazon Cognito 发送电子邮件消息，则它会调用 Lambda 函数，而不是其原定设置行为。使用自定义发件人触发器，您的 AWS Lambda 函数可以通过您选择的方法和提供商向用户发送电子邮件通知。您的函数的自定义代码必须处理和传递用户池中的所有电子邮件消息。

此触发器适用于以下场景：您可能希望更好地控制用户池发送电子邮件消息的方式。您的 Lambda 函数可以自定义对 Amazon SES API 操作的调用，例如，当您想要管理多个经过验证的身份或跨 AWS 区域时。您的函数还可能将消息重定向到另一个传递媒介或第三方服务。

要了解如何配置自定义电子邮件发件人触发器，请参阅[激活自定义发件人 Lambda 触发器](user-pool-lambda-custom-sender-triggers.md#enable-custom-sender-lambda-trigger)。

## 自定义电子邮件发件人 Lambda 触发器源
<a name="trigger-source"></a>

下表显示了 Lambda 代码中自定义电子邮件触发器源的触发事件。


| `TriggerSource value` | 事件 | 
| --- | --- | 
| CustomEmailSender\$1SignUp | 用户注册，Amazon Cognito 随即发送欢迎消息。 | 
| CustomEmailSender\$1Authentication | 用户登录，Amazon Cognito 发送电子邮件 OTP 或 MFA 代码。 | 
| CustomEmailSender\$1ForgotPassword | 用户请求代码以重置其密码。 | 
| CustomEmailSender\$1ResendCode | 用户请求替换账号确认码。 | 
| CustomEmailSender\$1UpdateUserAttribute | 用户更新电子邮件地址或电话号码属性，而 Amazon Cognito 将发送代码用于验证该属性。 | 
| CustomEmailSender\$1VerifyUserAttribute | 用户创建新电子邮件地址或电话号码属性，而 Amazon Cognito 将发送代码用于验证该属性。 | 
| CustomEmailSender\$1AdminCreateUser | 您在用户池中创建新用户，而 Amazon Cognito 向其发送临时密码。 | 
| CustomEmailSender\$1AccountTakeOverNotification | Amazon Cognito 检测到接管用户账户的尝试并向用户发送通知。 | 

## 自定义电子邮件发件人 Lambda 触发器参数
<a name="custom-email-sender-parameters"></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": {
        "type": "customEmailSenderRequestV1",
        "code": "string",
        "clientMetadata": {
            "string": "string",
             . . .
            },
        "userAttributes": {
            "string": "string",
            . . .
         }
}
```

------

### 自定义电子邮件发件人请求参数
<a name="custom-email-sender-request-parameters"></a>

**类型**  
请求版本。对于自定义电子邮件发件人事件，此字符串的值始终为 `customEmailSenderRequestV1`。

**代码**  
您的函数可以解密并发送给您的用户的加密代码。

**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 操作的数据。  
在具有以下触发源的事件中，Amazon Cognito 会向自定义电子邮件触发函数发送 `ClientMetadata`：  
+ `CustomEmailSender_ForgotPassword`
+ `CustomEmailSender_SignUp`
+ `CustomEmailSender_Authentication`
Amazon Cognito 不会在具有源 `CustomEmailSender_AccountTakeOverNotification` 的触发事件中发送 `ClientMetadata`。

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

### 自定义电子邮件发件人响应参数
<a name="custom-email-sender-response-parameters"></a>

Amazon Cognito 不需要自定义电子邮件发件人响应中有任何其他返回信息。您的 Lambda 函数必须解释事件并解密代码，然后传送消息内容。典型的函数会组装电子邮件消息并将其定向到第三方 SMTP 中继。

## 代码示例
<a name="custom-email-sender-code-examples"></a>

以下 Node.js 示例在您的自定义电子邮件发件人 Lambda 函数中处理电子邮件事件。此示例假设您的函数定义了两个环境变量。

**`KEY_ID`**  
要用于加密和解密用户代码的 KMS 密钥的 ID。

**`KEY_ARN`**  
要用于加密和解密用户代码的 KMS 密钥的 Amazon 资源名称 (ARN)。

**部署此函数**

1. 在开发者工作区中安装最新版本的 NodeJS。

1. 在您的工作区中新建一个 NodeJS 项目。

1. 使用 `npm init -y` 初始化您的项目。

1. 为 Lambda 函数 `touch index.mjs` 创建脚本。

1. 将以下示例的内容粘贴到 `index.mjs`。

1. 下载项目依赖关系， AWS Encryption SDK:`npm install @aws-crypto/client-node`.

1. 将项目目录压缩为文件 `zip -r my_deployment_package.zip .`。

1. [将该 ZIP 文件部署到函数](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-package.html)。

此函数示例会解密代码，并在注册事件中模拟向用户的电子邮件地址发送电子邮件消息。

```
import { KmsKeyringNode, buildClient, CommitmentPolicy } from '@aws-crypto/client-node';

// Configure the encryption SDK client with the KMS key from the environment variables
const { encrypt, decrypt } = buildClient(
    CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT
);

const generatorKeyId = process.env.KEY_ID;
const keyIds = [process.env.KEY_ARN];
const keyring = new KmsKeyringNode({ generatorKeyId, keyIds });

// Example function to simulate sending email.
// This example logs message details to CloudWatch Logs from your Lambda function.
// Update this function with custom logic that sends an email message to 'emailaddress' with body 'message'.
const sendEmail = async (emailAddress, message) => {
    // Log the destination with the email address masked.
    console.log(`Simulating email send to ${emailAddress.replace(/[^@.]/g, '*')}`);
    // Log the message with the code masked.
    console.log(`Message content: ${message.replace(/\b\d{6,8}\b/g, '********')}`);
    // Simulate API delay
    await new Promise(resolve => setTimeout(resolve, 100));
    console.log('Email sent successfully');
    return true;
};

export const handler = async (event) => {
    try {
        // Decrypt the secret code using encryption SDK
        let plainTextCode;
        if (event.request.code) {
            const { plaintext, messageHeader } = await decrypt(keyring, Buffer.from(event.request.code, 'base64'));
            plainTextCode = Buffer.from(plaintext).toString('utf-8');
        }

        // Handle different trigger sources
        if (event.triggerSource == 'CustomEmailSender_SignUp') {
            const emailAddress = event.request.userAttributes.email;
            const message = `Welcome! Your verification code is: ${plainTextCode}`;
            await sendEmail(emailAddress, message);
        }
        else if (event.triggerSource == 'CustomEmailSender_ResendCode') {
            // Handle resend code
        }
        else if (event.triggerSource == 'CustomEmailSender_ForgotPassword') {
            // Handle forgot password
        }
        else if (event.triggerSource == 'CustomEmailSender_UpdateUserAttribute') {
            // Handle update attribute
        }
        else if (event.triggerSource == 'CustomEmailSender_VerifyUserAttribute') {
            // Handle verify attribute
        }
        else if (event.triggerSource == 'CustomEmailSender_AdminCreateUser') {
            // Handle admin create user
        }
        else if (event.triggerSource == 'CustomEmailSender_Authentication') {
            // Handle authentication
        }
        else if (event.triggerSource == 'CustomEmailSender_AccountTakeOverNotification') {
            // Handle account takeover notification
        }

        return;
    } catch (error) {
        console.error('Error in custom email sender:', error);
        throw error;
    }
};
```

# 自定义 SMS 发件人 Lambda 触发器
<a name="user-pool-lambda-custom-sms-sender"></a>

当您为用户池分配自定义短信发件人触发器时，如果用户事件要求 Amazon Cognito 发送短信，则它会调用 Lambda 函数，而不是其原定设置行为。使用自定义发件人触发器，您的 AWS Lambda 函数可以通过您选择的方法和提供商向用户发送 SMS 通知。您的函数的自定义代码必须处理和传递用户池中的所有短信。

此触发器适用于以下场景：您可能希望更好地控制用户池发送短信消息的方式。您的 Lambda 函数可以自定义对 Amazon SNS API 操作的调用，例如，当您想要管理多个 IDs 起源或交叉时。 AWS 区域您的函数还可能将消息重定向到另一个传递媒介或第三方服务。

要了解如何配置自定义电子邮件发件人触发器，请参阅[激活自定义发件人 Lambda 触发器](user-pool-lambda-custom-sender-triggers.md#enable-custom-sender-lambda-trigger)。

## 自定义 SMS 发件人 Lambda 触发器源
<a name="trigger-source"></a>

下表显示了 Lambda 代码中自定义 SMS 触发器源的触发事件。


| `TriggerSource value` | 事件 | 
| --- | --- | 
| CustomSMSSender\$1SignUp | 用户注册，Amazon Cognito 随即发送欢迎消息。 | 
| CustomSMSSender\$1ForgotPassword | 用户请求代码以重置其密码。 | 
| CustomSMSSender\$1ResendCode | 用户请求新代码来确认其注册。 | 
| CustomSMSSender\$1VerifyUserAttribute | 用户创建新电子邮件地址或电话号码属性，而 Amazon Cognito 将发送代码用于验证该属性。 | 
| CustomSMSSender\$1UpdateUserAttribute | 用户更新电子邮件地址或电话号码属性，而 Amazon Cognito 将发送代码用于验证该属性。 | 
| CustomSMSSender\$1Authentication | 用户登录，Amazon Cognito 发送短信 OTP 或 MFA 代码。 | 
| CustomSMSSender\$1AdminCreateUser | 您在用户池中创建新用户，而 Amazon Cognito 向其发送临时密码。 | 

## 自定义 SMS 发件人 Lambda 触发器参数
<a name="custom-sms-sender-parameters"></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": {
        "type": "customSMSSenderRequestV1",
        "code": "string",
        "clientMetadata": {
            "string": "string",
             . . .
            },
        "userAttributes": {
            "string": "string",
            . . .
         }
}
```

------

### 自定义 SMS 发件人请求参数
<a name="custom-sms-sender-request-parameters"></a>

**类型**  
请求版本。对于自定义 SMS 发件人事件，此字符串的值始终为 `customSMSSenderRequestV1`。

**代码**  
您的函数可以解密并发送给您的用户的加密代码。

**clientMetadata**  
一个或多个键值对，您可以将它们作为自定义输入提供给自定义 SMS 发件人 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 操作的数据。

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

### 自定义 SMS 发件人响应参数
<a name="custom-sms-sender-response-parameters"></a>

Amazon Cognito 不需要响应中任何额外的返回信息。您的函数可以使用 API 操作来查询和修改资源，或者将事件元数据记录到外部系统。

## 代码示例
<a name="custom-sms-sender-code-examples"></a>

以下 Node.js 示例在您的自定义 SMS 发件人 Lambda 函数中处理 SMS 消息事件。此示例假设您的函数定义了两个环境变量。

**`KEY_ID`**  
要用于加密和解密用户代码的 KMS 密钥的 ID。

**`KEY_ARN`**  
要用于加密和解密用户代码的 KMS 密钥的 Amazon 资源名称 (ARN)。

**部署此函数**

1. 在开发者工作区中安装最新版本的 NodeJS。

1. 在您的工作区中新建一个 NodeJS 项目。

1. 使用 `npm init -y` 初始化您的项目。

1. 为 Lambda 函数 `touch index.mjs` 创建脚本。

1. 将以下示例的内容粘贴到 `index.mjs`。

1. 下载项目依赖关系， AWS Encryption SDK:`npm install @aws-crypto/client-node`.

1. 将项目目录压缩为文件 `zip -r my_deployment_package.zip .`。

1. [将该 ZIP 文件部署到函数](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-package.html)。

```
import { KmsKeyringNode, buildClient, CommitmentPolicy } from '@aws-crypto/client-node';

// Configure the encryption SDK client with the KMS key from the environment variables
const { encrypt, decrypt } = buildClient(
    CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT
);

const generatorKeyId = process.env.KEY_ID;
const keyIds = [process.env.KEY_ARN];
const keyring = new KmsKeyringNode({ generatorKeyId, keyIds });

// Example function to simulate sending SMS.
// This example logs message details to CloudWatch Logs from your Lambda function.
// Update this function with custom logic that sends an SMS message to 'phoneNumber' with body 'message'.
const sendSMS = async (phoneNumber, message) => {
    // Log the destination with the phone number masked.
    console.log(`Simulating SMS send to ${phoneNumber.replace(/[^+]/g, '*')}`);
    // Log the message with the code masked.
    console.log(`Message content: ${message.replace(/\b\d{6,8}\b/g, '********')}`);    
    // Simulate API delay
    await new Promise(resolve => setTimeout(resolve, 100));
    console.log('SMS sent successfully');
    return true;
};

export const handler = async (event) => {
    try {
        // Decrypt the secret code using encryption SDK
        let plainTextCode;
        if (event.request.code) {
            const { plaintext, messageHeader } = await decrypt(keyring, Buffer.from(event.request.code, 'base64'));
            plainTextCode = Buffer.from(plaintext).toString('utf-8');
        }

        // Handle different trigger sources
        if (event.triggerSource == 'CustomSMSSender_SignUp') {
            const phoneNumber = event.request.userAttributes.phone_number;
            const message = `Welcome! Your verification code is: ${plainTextCode}`;
            await sendSMS(phoneNumber, message);
        }
        else if (event.triggerSource == 'CustomSMSSender_ResendCode') {
            // Handle resend code
        }
        else if (event.triggerSource == 'CustomSMSSender_ForgotPassword') {
            // Handle forgot password
        }
        else if (event.triggerSource == 'CustomSMSSender_UpdateUserAttribute') {
            // Handle update attribute
        }
        else if (event.triggerSource == 'CustomSMSSender_VerifyUserAttribute') {
            // Handle verify attribute
        }
        else if (event.triggerSource == 'CustomSMSSender_AdminCreateUser') {
            // Handle admin create user
        }
        return;
    } catch (error) {
        console.error('Error in custom SMS sender:', error);
        throw error;
    }
};
```

**Topics**
+ [自定义 SMS 发件人 Lambda 触发器源](#trigger-source)
+ [自定义 SMS 发件人 Lambda 触发器参数](#custom-sms-sender-parameters)
+ [代码示例](#custom-sms-sender-code-examples)
+ [使用自定义 SMS 发件人函数评估 SMS 消息功能](#sms-to-email-example)

## 使用自定义 SMS 发件人函数评估 SMS 消息功能
<a name="sms-to-email-example"></a>

自定义 SMS 发件人 Lambda 函数接受您的用户池将发送的 SMS 消息，并且该函数根据您的自定义逻辑传送内容。Amazon Cognito 将 [自定义 SMS 发件人 Lambda 触发器参数](#custom-sms-sender-parameters) 发送到您的函数。您的函数可以用这些信息做您想做的事。例如，您可以将代码发送到 Amazon Simple Notification Service (Amazon SNS) 主题。Amazon SNS 主题订阅者可以是 SMS 消息、HTTPS 端点或电子邮件地址。

[要使用自定义短信发送器 Lambda 函数为 Amazon Cognito 短信创建测试环境，请参阅上的 aws-sample [amazon-cognito-user-pools development-and-testing-with 库sms-redirected-to-email中的--](https://github.com/aws-samples/amazon-cognito-user-pool-development-and-testing-with-sms-redirected-to-email)。 GitHub](https://github.com/aws-samples)存储库包含可以创建新用户池或使用已有的用户池的 AWS CloudFormation 模板。这些模板创建 Lambda 函数和 Amazon SNS 主题。模板分配为自定义 SMS 发件人触发器的 Lambda 函数将您的 SMS 消息重定向到 Amazon SNS 主题的订阅者。

当您将此解决方案部署到用户池时，对于 Amazon Cognito 通常通过 SMS 消息发送的所有消息，Lambda 函数将改为发送到中央电子邮件地址。使用此解决方案自定义和预览 SMS 消息，并测试促使 Amazon Cognito 发送 SMS 消息的用户池事件。完成测试后，回滚 CloudFormation 堆栈，或者从用户池中移除自定义短信发送器功能分配。

**重要**  
不要使用 [amazon-cognito-user-pool-development-and-testing-with-](https://github.com/aws-samples/amazon-cognito-user-pool-development-and-testing-with-sms-redirected-to-email) 中的模板sms-redirected-to-email来构建生产环境。解决方案中的自定义 SMS 发件人 Lambda 函数*模拟* SMS 消息，但 Lambda 函数将它们全部发送到一个中央电子邮件地址。在生产 Amazon Cognito 用户池中发送 SMS 消息之前，您必须完成 [Amazon Cognito 用户池的短信设置](user-pool-sms-settings.md)中显示的要求。