是否可以在Lambda触发器中修改AWS Cognito用户属性

alt*_*tus 18 triggers amazon-cognito aws-lambda

看一下AWS文档,

https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-预注册

您在Pre Sign-up Lambda功能中有以下参数 :

"request": {
  "userAttributes": {
    "string": "string",
    ....
},
"validationData": {<validation data as key-value (String, String) pairs, from the client>}
Run Code Online (Sandbox Code Playgroud)

有没有办法修改或添加其他userAttributes事件对象?

例如:

// Modify an existing username...
event.request.userAttributes.name.ucfirst();

// Add an additional attribute...
event.request.userAttributes.nickname = "ANY_NAME";


callback(null, event);
Run Code Online (Sandbox Code Playgroud)

Kho*_*hoi 9

是的,绝对有办法!您需要在Lambda处理程序中使用AWS javascript SDK:

const AWS = require('aws-sdk');
AWS.config.update({region: 'ap-southeast-1'});

const cognitoidentityserviceprovider =
  new AWS.CognitoIdentityServiceProvider({
    apiVersion: '2016-04-18'
  });
cognitoidentityserviceprovider.adminUpdateUserAttributes(
  {
    UserAttributes: [
      {
        Name: 'YOUR_USER_ATTRIBUTE_NAME',
        Value: 'YOUR_USER_ATTRIBUTE_VALUE'
      }
    ],
    UserPoolId: event.userPoolId,
    Username: event.userName
  },
  function(err, data) {
    ...
  }
);
Run Code Online (Sandbox Code Playgroud)

确保为Lambda函数提供正确的策略(即允许"cognito-idp:AdminUpdateUserAttributes"操作),并且用户池已定义属性.

  • 在预注册功能中,这对我不起作用;看来此时尚未创建用户。还有其他人可以使用吗? (3认同)
  • 由于用户尚不存在(当使用联合身份进行注册时),这似乎在确认后触发器中也会间歇性失败 (3认同)
  • 这并没有回答以下问题:有没有办法修改或添加事件对象的附加 userAttributes? (2认同)

per*_*pil 6

没有办法在注册期间改变/增强属性,但在登录期间,您可以使用预令牌生成触发器来改变/增强它们。

  • 我怀疑这是正确的答案,因为其他解决方案都不适合我。 (2认同)

Shi*_*nha 5

对于任何其他人想要深入了解这个问题,下面是一个例子

下面的 lambda 函数 #1 包含两个自定义属性idaethaddress. 在 Cognito 用户池的 PreSignUpHook 期间调用 lambda

#2(在事件更改日志之前)这些属性的原始值是ida=1ethaddress=ABCD

#3(事件更改日志后)反映了这些属性的更改值: ida=2ethaddress=EFGH

但是,保存到 cognito 的值是原始值:ida=1ethaddress=ABCD. 因此,在 presignuphook 期间更新 userAttributes 不会按照某些答案中的建议工作。

另外,当响应对象中的预定义属性被修改时,它们会按预期更新:

"response": {
    "autoConfirmUser": true,
    "autoVerifyEmail": false,
    "autoVerifyPhone": false
}
Run Code Online (Sandbox Code Playgroud) 1. 拉姆达:
'use strict';
global.fetch = require('node-fetch')

module.exports.preSignUp = async (event, context, callback) => {
// Set the user pool autoConfirmUser flag after validating the email domain

let data = await fetch("http://***.***.***/api/members/create",
{
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    method: "POST",
})
.then(res => res.json())
.then(res => res);

event.response.autoConfirmUser = true;
console.log('before event:', JSON.stringify(event)); 
event.request.userAttributes['custom:ethaddress'] = String(data.address); 
event.request.userAttributes['custom:ida'] = "2";  
console.log('Received event:', JSON.stringify(event));  
console.log('Address:', data.address);


 // Return to Amazon Cognito
callback(null, event);
 };
Run Code Online (Sandbox Code Playgroud) 2.

事件更改日志之前:

2019-01-20T01:02:24.639Z    edce636e-75ea-492b-b6a0-dd4f22dc9038    before event:
{
    "version": "1",
    "region": "us-east-1",
    "userPoolId": "us-east-1-*****",
    "userName": "*******@gmail.com",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "******************"
    },
    "triggerSource": "PreSignUp_SignUp",
    "request": {
        "userAttributes": {
            "custom:ida": "1",
            "custom:ethaddress": "ABCD",
            "email": "*******@gmail.com"
        },
        "validationData": {}
    },
    "response": {
        "autoConfirmUser": true,
        "autoVerifyEmail": false,
        "autoVerifyPhone": false
    }
}
Run Code Online (Sandbox Code Playgroud) 3 .

事件更改日志后:

Received event:
{
    "version": "1",
    "region": "us-east-1",
    "userPoolId": "us-east-1_0BaE6eaTY",
    "userName": "*******@gmail.com",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "*****************"
    },
    "triggerSource": "PreSignUp_SignUp",
    "request": {
        "userAttributes": {
            "custom:ida": "2",
            "custom:ethaddress": "EFGH",
            "email": "*******@gmail.com"
        },
        "validationData": {}
    },
    "response": {
        "autoConfirmUser": true,
        "autoVerifyEmail": false,
        "autoVerifyPhone": false
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:

似乎没有办法在 PRESIGNUP 过程中执行此操作,但是可以在下面提供的 Cognito 示例中将其作为 POSTCONFIRMATION 触发器执行。

需要注意的一些事情。

  1. 自定义属性已添加到 cognito 中并且是可变的。
  2. 在 App 客户端中 --> 显示详细信息 --> “设置属性读写权限” 确保自定义属性上有以下读写权限。
  3. 确保 lambda 函数具有允许其执行的角色:adminUpdateUserAttributes 例如,将 AmazonCognitoPowerUser 策略附加到 LambaRole。
module.exports.postConfirmation = async (event, context,callback) => {
        const cognitoIdServiceProvider = new CognitoIdentityServiceProvider({
          region: 'us-east-1'
        });

        var params =  {
            UserAttributes: [
              {
                  Name: 'custom:sillyName',
                  Value: 'customSillyName'
              }
            ],
            UserPoolId: event.userPoolId,
            Username: event.userName
        }

        cognitoIdServiceProvider.adminUpdateUserAttributes(params, function(err, data) {
          if (err) console.log(err, err.stack); // an error occurred
          else     console.log(data);           // successful response
        }); 

        callback(null,event);

};
Run Code Online (Sandbox Code Playgroud)

请注意,如果您尝试cognitoIdServiceProvider.adminUpdateUserAttributes在 preSignUp 触发器挂钩中使用用户;将收到一个异常,说明用户尚未退出


JJJ*_*idt 5

为了填写@Khoi 非常有用的答案的一些细节,并且对于所有剪切和粘贴的人(您知道自己是谁),这里有一个 Lambda 模板,该模板运行 Cognito 用户池后确认触发器。

Lambda 在用户的自定义属性中设置一个新值,在本例中为“fruit”。以下是实施雷区中需要避免的一些问题:

  1. 自定义属性必须在创建用户池时在用户池中定义,并且在定义属性时必须将其设置为Mutable 。
  2. 将 Lambda 部署到您的 AWS 账户后,您需要通过 AWS 控制台中的用户池配置页面将确认后触发器指向此 Lambda。
    服务->Cognito->管理用户池->您的用户池->触发器->确认后
  3. Lambda 需要更新用户池属性的权限,这是通过将 IAM 策略附加到允许“cognito-idp:AdminUpdateUserAttributes”操作的 Lambda 来完成的。请参阅下面的示例。
  4. 您可以使用前缀custom:访问该属性,如custom:fruit
  5. 自定义属性中的冒号使 Javascript 不高兴,因此当从 CognitoUser 对象访问客户端中的自定义属性时,例如从 Amplify signIn() 方法,您需要使用
    let a = user.attributes['custom:fruit']

样品 Lambda

    const aws = require('aws-sdk');
    const cisProvider = new aws.CognitoIdentityServiceProvider({ apiVersion: '2016-04-18' });

    // Cognito User Pool Lambda triggers are documented here:
    // https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html
    exports.lambdaHandler = async (event, context, callback) => {

        const params = {
            UserPoolId: event.userPoolId,
            Username: event.userName,
            UserAttributes:  // this parameter needs to be an array
                [
                    {
                        Name: 'custom:fruit',
                        Value: 'banana'
                    }
                ]
        };

        if (event.request.userAttributes.email) {
            try {
                await cisProvider
                    .adminUpdateUserAttributes(params)
                    .promise();

                console.log('Success');
            } catch (error) {
                console.error('Error', error);
            }
        }

        callback(null, event);
    };
Run Code Online (Sandbox Code Playgroud)

SAM YAML 模板

如果您正在使用 AWS SAM(正如我希望的那样)来调试和部署 Lambda,那么这里是该 Lambda 的模板。请注意角色资源。在部署 Lambda 之前,您需要在 AWS 控制台中定义此 IAM 角色。可能有一种方法可以在模板中定义角色,但我不是 AWS YAML 方面的专家。使用 SAM CLI 命令将 Lambda 部署到您的 AWS 账户
sam deploy --guided

  AWSTemplateFormatVersion: '2010-09-09'
  Transform: AWS::Serverless-2016-10-31
  Description: >
    SAM Template for lambda function that runs as a Cognito User Pool post confirmation trigger.
    Cognito invokes this function when a new user signs up.
    
  Globals:
    Function:
      Timeout: 3

  Resources:
    PostConfirmationFunction:
      Type: AWS::Serverless::Function
      Properties:
        CodeUri: post-confirmation/
        Handler: app.lambdaHandler
        Runtime: nodejs14.x
        Role:
          # This role gives Lambda permission to update user pool attributes as well as basic execution.
          arn:aws:iam::xxxxxxxxxxxx:role/lambda-cognito-update-role

  Outputs:
    PostConfirmationFunction:
      Description: "Post Confirmation Lambda Function ARN"
      Value: !GetAtt PostConfirmationFunction.Arn
Run Code Online (Sandbox Code Playgroud)

IAM 角色

您需要在 IAM 控制台中创建一个包含更新用户属性的权限的角色。我更喜欢使用“内联策略”来执行此操作,以避免我的账户中 IAM 策略激增且依赖性不明确。我发现做到这一点的最佳方法是两步过程:

  1. 在 IAM 控制台中创建一个与 YAML 模板中列出的名称相同的角色,在本示例中为 lambda-cognito-update-role在权限步骤中附加 AWSLambdaBasicExecutionRole ,并为其指定角色名称lambda-cognito-update-role
  2. 在 AWS 控制台的 IAM 部分的角色下,找到您新创建的角色并单击将其打开。
    • 当您在此处时,将角色 ARN 从摘要页面顶部复制到 SAM YAML 模板中。
    • 单击右侧的添加内联策略,单击 JSON 选项卡,然后使用以下 JSON 覆盖样板:
{
  "Version": "2012-10-17",
  "Statement": [
    {
        "Sid": "CognitoUpdate",
        "Effect": "Allow",
        "Action": "cognito-idp:AdminUpdateUserAttributes",
        "Resource": "*"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

可以说,资源应该更具体,可能仅限于您帐户中的用户池。我将其留给您自行决定。