如何在创建 Amazon Cognito 用户池后更改其属性?

上次更新时间:2019 年 6 月 24 日

我创建了一个 Amazon Cognito 用户池,现在我想更改用户注册所需的标准属性。如何更改属性?

简短描述

创建用户池后,您不能更改标准用户池属性。但是,您可以创建新用户池,使其具有用户注册所需的属性。然后,通过将 AWS Lambda 用作用户迁移触发器,将现有用户迁移到新用户池

注意:您可以将自定义属性添加到现有用户池,但这些属性并非用户注册所需。

解决方法

设置新用户池,使其具有不同的属性

创建新用户池。然后,在设置过程中(在结束时选择创建池之前),将标准属性编辑到您的首选项。

重要提示:如果在用户池中指定新的必需属性,必须将 Lambda 函数设计为向新用户池提供这些新属性,否则用户迁移期间身份验证将失败。例如,假如您只需要旧用户池中的电子邮件,但现在您需要新的用户池中同时有电子邮件电话号码。在这种情况下,您必须将电话号码的属性值传递到的新用户池才能成功对用户进行身份验证。

创建 Lambda 函数

使用 Lambda 控制台编辑器或通过构建并上传您自己的部署程序包,创建用户迁移 Lambda 函数。

下面是一个可用于测试的 Python 函数示例:

注意:对于 UserPoolId,使用旧用户池的 ID 替换示例值。在 Amazon Cognito 控制台中,进入用户池的管理页面,在常规设置选项卡上可以找到此 ID。对于 ClientId, 使用旧用户池的应用程序客户端 ID 替换示例值。也可以在 Amazon Cognito 控制台中找到此应用程序客户端 ID,也 一般设置下,选择应用程序客户端

重要提示:此示例代码无法正常迁移使用旧用户池中的多重身份验证 (MFA) 的用户。

# Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import json
import boto3

client = boto3.client('cognito-idp')

def lambda_handler(event, context):
    if (event['triggerSource'] == 'UserMigration_Authentication'):
        user = client.admin_initiate_auth(
            UserPoolId='<user pool id of the user pool where the user already exists>',
            ClientId='<app client id of the user pool where the user already exists>',
            AuthFlow='ADMIN_NO_SRP_AUTH',
            AuthParameters={
                'USERNAME': event['userName'],
                'PASSWORD': event['request']['password']
            }
        )
        
        if (user):
            userAttributes = client.get_user(
                AccessToken=user['AuthenticationResult']['AccessToken']
            )
            for userAttribute in userAttributes['UserAttributes']:
                if userAttribute['Name'] == 'email':
                    userEmail = userAttribute['Value']
                    #print(userEmail)
                    event['response']['userAttributes'] = {
                        "email": userEmail,
                        "email_verified": "true"
                    }
            
            event['response']['messageAction'] = "SUPPRESS"
            print (event)
            return (event)
        else:
            return('Bad Password')
    elif (event["triggerSource"] == "UserMigration_ForgotPassword"):
        user = client.admin_get_user(
            UserPoolId='<user pool id of the user pool where the already user exists>',
            Username=event['userName']
        )
        if (user):
            for userAttribute in user['UserAttributes']:
                if userAttribute['Name'] == 'email':
                    userEmail = userAttribute['Value']
                    print(userEmail)
                    event['response']['userAttributes'] = {
                        "email": userEmail,
                        "email_verified": "true"
                    }
            event['response']['messageAction'] = "SUPPRESS"
            
            print (event)
            return (event)
        else:
            return('Bad Password')
            
    else:
        return('there was an error')

将向用户迁移触发器添加到新用户池

Amazon Cognito 控制台中,将新的 Lambda 函数设置为用户迁移 Lambda 触发器。有关更多信息,请参阅添加用户池 Lambda 触发器

启用用户迁移的 USER_PASSWORD_AUTH 流程

配置用户池应用程序客户端,以在迁移时使用 USER_PASSWORD_AUTH 身份验证流程。这让应用程序将用户的用户名和密码传递到 Lambda 函数,然后从现有用户池对其进行身份验证。

如果用户在旧用户池中存在,但在新用户池中不存在,则将逻辑添加到您的应用程序,以将默认身份验证流程更改为 USER_PASSWORD_AUTH 流程,再尝试登录。

例如,如果您的应用程序使用 JavaScript,您需要指定 cognitoUser.setAuthenticationFlowType 作为 USER_PASSWORD_AUTH

注意:您的用户迁移后,最好将您的应用程序身份验证流程更改为 USER_SRP_AUTH。此流程使用安全远程密码 (SRP) 协议对用户进行身份验证,无需通过网络发送密码。此流程还通过 USER_PASSWORD_AUTH 流程提供安全优势。有关更多信息,请参阅用户迁移身份验证流程使用用户池进行身份验证

cognitoUser.setAuthenticationFlowType('USER_PASSWORD_AUTH');

    cognitoUser.authenticateUser(authenticationDetails, {
        onSuccess: function(result) {
            // User authentication was successful
        },
        onFailure: function(err) {
            // User authentication was not successful
        },
        mfaRequired: function (codeDeliveryDetails) {
            // MFA is required to complete user authentication.
            // Get the code from user and call
            cognitoUser.sendMFACode(verificationCode, this);
        }
    });

有关更多信息,请参阅示例:使用 Lambda 触发器迁移 JavaScript 用户

测试设置

使用 Amazon Cognito 托管 Web UI 登录到您的应用程序,以测试身份验证流程。使用新用户池验证您登录所用的用户,然后将其迁移。

注意:如果您没有可用于登录测试的用户账户,请创建一个新用户

故障排除

如果在测试过程中收到一条错误消息,如“Exception during user migration”(用户迁移过程中出现异常),请启用 Lambda 的日志记录语句。这会将用户迁移 Lambda 触发器的参数记录到 Amazon CloudWatch Logs

复制此错误,然后查看日志,确定用户迁移 Lambda 触发器中是否有任何参数问题或语法错误。