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

时间:2018-01-28 14:11:29

标签: triggers aws-lambda amazon-cognito

查看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-signup

您在 预注册 Lambda功能中可以使用以下参数:

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

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

例如:

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

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


callback(null, event);

6 个答案:

答案 0 :(得分:7)

是的,绝对有办法!您需要在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) {
    ...
  }
);

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

答案 1 :(得分:4)

在注册过程中,没有办法改变/扩充属性,但在登录期间,您可以使用pre-token generation trigger对其进行变异/扩充。

答案 2 :(得分:1)

对于任何想了解这个问题的人,下面是一个示例

下面的lambda函数#1具有两个自定义属性idaethaddress。 Lambda在Cognito用户池的PreSignUpHook期间被调用

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

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

但是保存到认知模式的值是原始值:ida=1ethaddress=ABCD。因此,按照某些答案中的建议,无法在presignuphook期间更新userAttributes。

另一方面,修改响应对象中的预定义属性后,它们会按预期进行更新:

"response": {
    "autoConfirmUser": true,
    "autoVerifyEmail": false,
    "autoVerifyPhone": false
}
1. LAMBDA:
'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);
 };
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
    }
}
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
    }
}

更新:

在PRESIGNUP过程中似乎没有办法做到这一点 但是,在下面提供的cognito示例中,可以将其作为POSTCONFIRMATION触发器。

需要注意的一些事情。

  1. 自定义属性已添加到cognito中并且是可变的。
  2. 在应用程序客户端中
  3. ->显示详细信息->“设置属性读写权限” 确保自定义属性的读写权限位于下面。
  4. 确保lambda函数具有一个允许执行的ROLE:adminUpdateUserAttributes 例如。将AmazonCognitoPowerUser策略附加到LambaRole。

module.exports.postConfirmation =异步(事件,上下文,回调)=> {

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);

};

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

答案 3 :(得分:1)

要填写有关@Khoi 非常有用的答案的一些详细信息,以及对于所有剪辑师(您知道自己是谁),这里是一个运行 Cognito 用户池发布确认触发器的 Lambda 模板。

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

  1. 自定义属性必须在创建用户池时在用户池中定义,并且必须在定义时设置属性可变。立>
  2. 将 Lambda 部署到您的 AWS 账户后,您需要通过 AWS 控制台中的用户池配置页面将发布确认触发器指向此 Lambda。
    服务->认知->管理用户池->您的用户池->触发器->发布确认
  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);
    };

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

IAM 角色

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

  1. 在 IAM 控制台中创建一个与 YAML 模板中列出的名称相同的角色,在本示例中为 lambda-cognito-update-role。在 Permissions 步骤中附加 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": "*"
    }
  ]
}

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

答案 4 :(得分:0)

当然可以。您需要使用 AWS 开发工具包。

const AWS = require('aws-sdk');
const config = require('./config'); 

function updateAttribute(params) {
    AWS.config.update({
        'region' : config.AWSConfig.region,
        'accessKeyId': config.AWSConfig.accessKeyId,
        'secretAccessKey': config.AWSConfig.secretAccessKey
    });
    let cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider();

    let parameters = { UserPoolId : config.userPoolDetails.userPoolId,
    Username : params.userName,
    UserAttributes : [
        {
            'Name': params.nameOfAttribute ,
            'Value': params.newValueOfAttribute
        },
    ]}
    
    cognitoIdentityServiceProvider.adminUpdateUserAttributes(parameters,function (err, result) {
        if(err)
        console.log(err);
        else
        console.log("Attribute updated successfully");
    })
}

let params = {
    userName : 'username',
    nameOfAttribute : 'name',
    newValueOfAttribute : 'Sachin'
}

updateAttribute(params);

您甚至可以像这样添加新属性。

你可以在这里阅读更多: https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminUpdateUserAttributes.html

答案 5 :(得分:-2)

嗯,简单的解决方案就是这样, 将此添加到“ Pre Sign-up Lambda函数”中,以从您的代码中获取提示:

// Modify an existing username...
 event['request']['userAttributes']['name'] = "My_NAME";

// Add an additional attribute...
 event['request']['userAttributes']['custom:sillyname'] = "ANY_NAME";

 callback(null, event);

考虑到您已经为用户池添加了custom:sillyname属性。