如何在 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 REGION

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

  5. 安装 @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 生成的临时密码和授权代码。

  1. 使用以下命令创建 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_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 REGION

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

  2. 向 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 替换为您的区域代码。

  3. 更新 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 官方
AWS 官方已更新 1 年前