如何在 Amazon Cognito 用户群体中使用自定义电子邮件发件人 Lambda 触发器?

4 分钟阅读
0

我必须调用 Amazon Cognito 自定义电子邮件发件人 AWS Lambda 触发器才能处理和传送电子邮件。

解决方法

使用 Amazon Cognito 自定义电子邮件发件人触发器来允许第三方提供商通过您的 Lambda 函数代码向您的用户发送电子邮件通知。Amazon Cognito 向 Lambda 函数发送电子邮件请求。然后,Lambda 函数处理并传送电子邮件。

创建 Lambda 函数来用作您的自定义电子邮件发件人触发器

1.    创建名为 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 文件中添加相关代码,以便从您的自定义电子邮件提供商向用户发送电子邮件。

2.    创建 .zip 文件存档,也称为压缩的 index.js 文件:

$ zip function.zip index.js

3.    打开 Lambda 控制台

4.    使用 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 <specify a region>

**注意:**请将 <ExecutionRoleARN> 替换为您想要与 Lambda 函数关联的 AWS Identity and Access Management (IAM) 角色 Amazon 资源名称 (ARN)。有关更多详细信息,请参阅 Lambda 执行角色。您可以将 CustomEmailSender 替换为您选择的函数名称。请将 <specify a region> 替换为您的 AWS 区域代码。

5.    安装 @aws-crypto/client-node 模块以使用 AWS Encryption SDK。

如果未安装 @aws-crypto/client-node 模块,则必须完成以下高级任务:

  • 安装模块。
  • 打包最新版本的模块。
  • 创建包含您可以对 Lambda 函数使用的依赖项的 Lambda 层。

**注意:**请在与 Lambda 兼容的本地开发环境中运行安装命令。

创建工作目录:

$ mkdir -p aws-crypto-layer/nodejs

更改工作目录:

$ cd aws-crypto-layer/nodejs

使用 npm 包管理器安装最新版本的 aws-crypto 模块:

$ npm install @aws-crypto/client-node

**注意:**最佳做法是在开发 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 <specify a region>

将 Lambda 层添加到您的函数:

$ aws lambda update-function-configuration --function-name CustomEmailSender --layers arn:aws:lambda:us-east-2:123456789012:layer:node_crypto:1 --region <specify a region>

**注意:**请将 CustomEmailSender 替换为您的函数的名称。请将 arn:aws:lambda:us-east-2:123456789012:layer:node_crypto:1 替换为 publish-layer-version 命令输出中的 LayerVersionArn 值。请将 <specify a region> 替换为您的区域代码。

在 AWS KMS 中创建加密密钥

Amazon Cognito 使用 AWS Key Management Service (AWS KMS) 对称加密密钥来加密由 Amazon Cognito 生成的临时密码和授权代码。

1.    创建 AWS KMS 密钥:

$ aws kms create-key --description "KMS Key for CustomEmailSender" --region <specify a region>

**注意:**请将 <specify a 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 <specify a region>

**注意:**请将 <KeyId> 替换为 create-key 命令输出中的密钥 ID 值。请将 <specify a region> 替换为您的区域代码。

该代码示例依赖环境变量 KEY_ALIASKEY_ARN 来获取加密密钥信息。您必须在 CustomEmailSender Lambda 触发器中配置这些环境变量。

$ aws lambda update-function-configuration --function-name CustomEmailSender --environment 'Variables={KEY_ALIAS=alias/custom-email-key,KEY_ARN=<key_ARN>}' --region <specify a region>

**注意:**请将 CustomEmailSender 替换为您的 Lambda 函数名称。请将 alias/custom-email-key 替换为您的 AWS KMS 密钥的密钥别名。请将 <key_ARN> 替换为 create-key 命令输出中的 ARN 值。请将 <specify a region> 替换为您的区域代码。

向 Amazon Cognito 服务主体 cognito-idp.amazonaws.com 授予调用 Lambda 函数的权限

使用以下命令向 Amazon Cognito 服务主体授予调用 Lambda 函数的权限:

$ aws lambda add-permission --function-name CustomEmailSender --statement-id "CognitoLambdaInvokeAccess" --action lambda:InvokeFunction --principal cognito-idp.amazonaws.com --source-arn <UserPoolArn> --region <specify a region>

**注意:**请将 CustomEmailSender 替换为您的 Lambda 函数名称。请将 <UserPoolArn> 替换为您的用户群体 ARN。要查找用户群体 ARN,请打开 Amazon Cognito 控制台“用户群体”页面。然后,从列表中选择用户群体。或者,运行 describe-user-pool 命令。请将 <specify a region> 替换为您的区域代码。

更新 Amazon Cognito 用户群体,使其使用自定义电子邮件发件人 Lambda 触发器

通过在 UpdateUserPool API 中设置 CustomEmailSender 参数来更新用户群体。UpdateUserPool 需要用户群体的所有现有参数以及您要更改的参数。Amazon Cognito 会将任何缺失参数的值设置为其默认值。有关详细信息,请参阅更新用户群体配置

在以下示例中,仅 --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 <specify a region>

**注意:**请将 <LambdaArn> 替换为 create-function 命令输出中函数的 ARN 值。请将 <KMSKeyArn> 替换为 create-key 命令输出中提供的 ARN 值。请将 <UserPoolId> 替换为您的 Amazon Cognito 用户群体 ID。请将 <specify a 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 日志组中看到完整的日志。有关如何查看这些日志的更多详细信息,请参阅访问 AWS Lambda 的 Amazon CloudWatch 日志

AWS 官方
AWS 官方已更新 1 年前