Knowledge Center Monthly Newsletter - March 2025
Stay up to date with the latest from the Knowledge Center. See all new and updated Knowledge Center articles published in the last month and re:Post’s top contributors.
如何在 Amazon Cognito 用户池中使用自定义电子邮件发件人 Lambda 触发器?
我想要调用 Amazon Cognito 自定义电子邮件发件人 AWS Lambda 触发器来处理和传送电子邮件。
解决方法
使用 Amazon Cognito 自定义电子邮件发件人触发器来允许第三方提供商通过您的 Lambda 函数代码向您的用户发送电子邮件通知。Amazon Cognito 向 Lambda 函数发送电子邮件请求。然后,Lambda 函数处理并传送电子邮件。
创建 Lambda 函数来用作您的自定义电子邮件发件人触发器
-
创建名为 index.js 的文件,将以下代码添加到该文件中,然后保存您的更改。
const AWS = require('aws-sdk');const b64 = require('base64-js'); const encryptionSdk = require('@aws-crypto/client-node'); // Configure the encryption SDK client with the KMS key from the environment variables. const { encrypt, decrypt } = encryptionSdk.buildClient(encryptionSdk.CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT); const generatorKeyId = process.env.KEY_ALIAS; const keyIds = [ process.env.KEY_ARN ]; const keyring = new encryptionSdk.KmsKeyringNode({ generatorKeyId, keyIds }) exports.handler = async (event) => { // Decrypt the secret code using encryption SDK. let plainTextCode; if(event.request.code){ const { plaintext, messageHeader } = await decrypt(keyring, b64.toByteArray(event.request.code)); plainTextCode = plaintext } // PlainTextCode now has the decrypted secret. if(event.triggerSource == 'CustomEmailSender_SignUp'){ // Send email to end-user using custom or 3rd party provider. // Include temporary password in the email. console.log("CustomEmailSender_SignUp: " + plainTextCode); }else if(event.triggerSource == 'CustomEmailSender_ResendCode'){ console.log("CustomEmailSender_ResendCode: " + plainTextCode); }else if(event.triggerSource == 'CustomEmailSender_ForgotPassword'){ console.log("CustomEmailSender_ForgotPassword: " + plainTextCode); }else if(event.triggerSource == 'CustomEmailSender_UpdateUserAttribute'){ console.log("CustomEmailSender_UpdateUserAttribute: " + plainTextCode); }else if(event.triggerSource == 'CustomEmailSender_VerifyUserAttribute'){ console.log("CustomEmailSender_VerifyUserAttribute: " + plainTextCode); }else if(event.triggerSource == 'CustomEmailSender_AdminCreateUser'){ console.log("CustomEmailSender_AdminCreateUser: " + plainTextCode); }else if(event.triggerSource == 'CustomEmailSender_AccountTakeOverNotification'){ console.log("CustomEmailSender_AccountTakeOverNotification: " + plainTextCode); } return; };
**警告:**此代码的脚本用于解密加密的密钥。密钥是由 Amazon Cognito 发送的临时密码和授权代码。该脚本还会在日志中输出明文代码以用于演示目的。但是,以明文记录密钥是一个安全问题。当您的应用程序进入生产环境时,切勿在日志中输出解密的密钥。
在 index.js 文件中添加相关代码,以便从您的自定义电子邮件提供商向用户发送电子邮件。 -
创建 .zip 文件存档,也称为压缩的 index.js 文件:
$ zip function.zip index.js
-
打开 Lambda 控制台。
-
使用 Node.js 运行时创建 Lambda 函数。
以下是使用 Node.js 14.x 运行时创建 Lambda 函数的 AWS 命令行界面(AWS CLI)命令示例。
**注意:**如果在运行 AWS CLI 命令时收到错误,请确保您使用的是最新版本的 AWS CLI。$ aws lambda create-function --function-name CustomEmailSender --runtime nodejs14.x --handler index.handler --zip-file fileb://function.zip --role ExecutionRoleARN --region REGION
**注意:**将 ExecutionRoleARN 替换为您想要与 Lambda 函数关联的 AWS Identity and Access Management(IAM)角色 Amazon 资源名称(ARN)。有关更多详细信息,请参阅 Lambda 执行角色。您可以将 CustomEmailSender 替换为您选择的函数名称。将 REGION 替换为您的 AWS 区域代码。
-
安装 @aws-crypto/client-node 和 base64-js 模块以使用 AWS Encryption SDK。
如果您没有安装 @aws-crypto/client-node 模块,请执行以下操作。确保在与 Lambda 兼容的本地开发环境中运行安装命令:
创建工作目录:$ mkdir -p aws-crypto-layer/nodejs
更改工作目录:
$ cd aws-crypto-layer/nodejs
使用 npm 包管理器安装最新版本的 aws-crypto 模块:
$ npm install @aws-crypto/client-node $ npm install base64-js
**注意:**最佳实践是在开发 Lambda 资源时使用 Amazon Linux 2 环境。使用 Windows 或 macOS 操作系统进行开发时,请使用 Docker 安装 aws-crypto 模块:
$ docker run --entrypoint "" -v "$PWD":/var/task "public.ecr.aws/lambda/nodejs:14" /bin/sh -c "npm install @aws-crypto/client-node; exit"
创建一个 .zip 文件来上传到您的 Lambda 层:
$ zip -r ../package.zip ../
创建包含最新版本的 @aws-crypto/client-node 模块的 Lambda 层:
$ aws lambda publish-layer-version --layer-name node_crypto --description "My layer" --license-info "MIT" --compatible-runtimes nodejs14.x --zip-file fileb://../package.zip --region REGION
将 Lambda 层添加到您的函数:
$ aws lambda update-function-configuration --function-name CustomEmailSender --layers arn:aws:lambda:us-east-2:123456789012:layer:node_crypto:1 --region REGION
**注意:**请将 CustomEmailSender 替换为您的函数的名称。请将 arn:aws:lambda:us-east-2:123456789012:layer:node_crypto:1 替换为 publish-layer-version 命令输出中的 LayerVersionArn 值。将 REGION 替换为您的 AWS 区域代码。
在 AWS KMS 中创建加密密钥
Amazon Cognito 使用 AWS Key Management Service(AWS KMS)对称加密密钥来加密由 Amazon Cognito 生成的临时密码和授权代码。
-
使用以下命令创建 AWS KMS 密钥:
$ aws kms create-key --description "KMS Key for CustomEmailSender" --region REGION
**注意:**将 REGION 替换为您的区域代码。
由于此命令未指定密钥政策,因此分配了默认密钥政策。要将自定义密钥政策应用于您的 AWS KMS 密钥,请使用 JSON 策略将 --policy 参数添加到命令。确保向执行 UpdateUserPool 操作的 IAM 实体授予 kms:CreateGrant 权限,以添加自定义电子邮件触发器。
运行 create-key 命令时无法指定别名。要为新的 KMS 密钥创建别名,请使用 create-alias 命令:$ aws kms create-alias --alias-name alias/custom-email-key --target-key-id KeyId --region REGION
**注意:**将 Keyid 替换为 create-key 命令输出中的密钥 ID 值。将 REGION 替换为您的区域代码。
该代码示例依赖环境变量 KEY_ALIAS 和 KEY_ARN 来获取加密密钥信息。您必须在 CustomEmailSender Lambda 触发器中配置这些环境变量。$ aws lambda update-function-configuration --function-name CustomEmailSender --environment 'Variables={KEY_ALIAS=alias/custom-email-key,KEY_ARN=key_ARN}' --region REGION
**注意:**请将 CustomEmailSender 替换为您的 Lambda 函数名称。请将 alias/custom-email-key 替换为您的 AWS KMS 密钥的密钥别名。请将 key_ARN 替换为 create-key 命令输出中的 ARN 值。将 REGION 替换为您的区域代码。
-
向 Amazon Cognito 服务主体授予 cognito-idp.amazonaws.com 权限以调用 Lambda 函数。使用以下命令向调用 Lambda 函数的 Amazon Cognito 服务主体授予权限。
$ aws lambda add-permission --function-name CustomEmailSender --statement-id "CognitoLambdaInvokeAccess" --action lambda:InvokeFunction --principal cognito-idp.amazonaws.com --source-arn UserPoolArn --region REGION
**注意:**请将 CustomEmailSender 替换为您的 Lambda 函数名称。将 UserPoolArn 替换为您的用户池 ARN。要查找用户池 ARN,请打开 Amazon Cognito 控制台“用户池”页面。然后,从列表中选择用户群体。或者,运行 describe-user-pool 命令。将 REGION 替换为您的区域代码。
-
更新 Amazon Cognito 用户池,使其使用自定义电子邮件发件人 Lambda 触发器。在 UpdateUserPool API 中设置 CustomEmailSender 参数。UpdateUserPool 需要用户池的所有现有参数以及您要更改的参数。Amazon Cognito 会将任何缺失参数的值设置为其默认值。有关详细信息,请参阅 Updating user pool configuration。
在以下示例中,仅 --lambda-config 参数用于 CustomEmailSender Lambda 函数详细信息。因此,该命令会将自定义电子邮件发件人触发器添加到您的用户群体,并将剩余用户群体参数设置为默认值。如果为用户群体配置了非默认值,请在 update-user-pool 命令中传递这些值以避免将其设置为默认值。$ aws cognito-idp update-user-pool --lambda-config "CustomEmailSender={LambdaVersion=V1_0,LambdaArn= LambdaARN},KMSKeyID=KMSKeyARN" --user-pool-id UserPoolId --region REGION
**注意:**将 LambdaARN 替换为 create-function 命令输出中函数的 ARN 值。将 KMSKeyARN 替换为 create-key 命令输出中提供的 ARN 值。将 UserPoolId 替换为您的 Amazon Cognito 用户池 ID。将 REGION 替换为您的区域代码。
测试功能
要测试 Lambda 函数的集成,请模拟用户群体中用户的电子邮件发件人操作,例如电子邮件验证或密码恢复。以下示例显示了 Amazon Cognito 发送给 Lambda 函数的 ForgotPassword 事件。
{ version: '1', triggerSource: 'CustomEmailSender_ForgotPassword', region: 'us-east-1', userPoolId: 'us-east-1_xxxxxxxx', userName: 'example_user', callerContext: { awsSdkVersion: 'aws-sdk-unknown-unknown', clientId: '12a3b4example-clientid' }, request: { type: 'customEmailSenderRequestV1', code: 'XXXXeBlI7XP3RQmipedVF+7OGa4AgQACABVhdXXXXXXXvLXB1YmxpYy1rZXkAREF6Zk9NR2lBR0FUeDRITStmRHl4RDJyNlpqa2wvWktBbG45ckRmTEpMZ1A3THp4ME9RaVVjVHl3MVFOSEZjS3piZz09AAt1c2VycG9vbC1pZAATdXMtZWFzdC0xX29DOUhnUHVKWgABAAdhd3Mta21zAEthcm46XXdzOmttczp1cy1lYXN0LTE6XXX3XXc0NDA5OXXzOmtleS8yNmQ0ZjVmMy00YmZhLTQ0OXXtODUxZS01ZTM2ZWIwYjhmYjMAuAECAQB42Am0o+Rx0MgG+wLLyKtm1/vTm03JK3jQBZxqABAkreYBMOoAUtm3mLS7+kb2VL0SHgAAAH4wfAYJKoZIhvcNAQcGoG8wbQIBADBoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHjPPHlSWPt+UKrQOQIBEIA7oFUeGe2NPX2cuEVi+Qxwp8/IH1bgyYQut+QbbkElc1rXXXXXbeEVMjMkFQmQufmJyag9v1f+PUalvXwXAAAAAAwAABAAAAAAAAAAAAAAAAAAscZHg8dY/cKTskGQc065mv////8AAAABAAAAAAAAAAAAAAABAAAABpofXaVnP4pmf+yMoCElrOGy7Gn8pIUAZzBlAjEAn/7tuTNko8/HCwXXXXlCOJDeU0SSyB7o9y0TXHM7GptdvmB1JL9OzLxmUg6zChIhAjAFFbH4NrSblvwh/m0inDc11BpeOSKghtg8Pg5Nkf8eY6vmXX6GxjaCuyhBSO7IDcM=', clientMetadata: null, userAttributes: { sub: '1a2b3cde-33cd-402f-5g67-examplesub', 'cognito:user_status': 'CONFIRMED', email_verified: 'true', email: 'user@example.com' } } }
以下示例是明文代码形式的响应:
CustomEmailSender_ForgotPassword: 12345
您可以在为您的 Lambda 函数创建的 Amazon CloudWatch 日志组中看到完整的日志。有关如何查看这些日志的更多详细信息,请参阅使用 Amazon CloudWatch Logs 与 AWS Lambda。
安装 @aws-crypto/client-node 和 base64-js 模块以使用 AWS Encryption SDK。

相关内容
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前