AWS Amplify:如何为基于电子邮件的身份验证映射社交提供商属性?

dan*_*nca 8 federated-identity amazon-web-services amazon-cognito aws-amplify

我有一个使用 AWS Amplify 构建的 React Web 应用程序我已经添加了 Cognito 用户池的身份验证,我没有使用用户名,我只使用电子邮件/电话选择了登录,我不想要用户名,但 Cognito 还是创建了一个随机用户名.

我希望用户使用他们的电子邮件或使用一个社交提供商(Facebook 或 Google)登录,这无关紧要,他们应该可以根据电子邮件访问同一个帐户。

我认为很正常的做法。但是,当我第一次尝试使用社交提供商登录时,我注意到 Cognito 没有为我提供相同的帐户,而是创建了一个新帐户,使用不同的用户名,并在用户池中将 EXTERNAL_PROVIDER 作为帐户状态

所以,我认为这可能只是一些映射不正确,我去了联邦部分的属性映射,我看到 Facebook Id 和 Google Sub 被分配给用户名,我试图删除它,为了我的令人惊讶的是,它被分配回了用户名。然后我想“我可以创建一个自定义属性来存储该信息,它应该没问题”。

所以我这样做了,为 Facebook 创建了一个属性,为 GoogleId 创建了一个属性......再次尝试......不,仍然回到用户名,但没有错误消息,什么都没有......

我去寻求帮助文档并找到了这个

目前,只有 Facebook id、Google sub、login with Amazon user_id 和 Sign in with Apple sub 属性可以映射到 Amazon Cognito 用户池用户名属性。

如果这总是将每个提供者 ID 与用户名相关联,那么就无法合并这些帐户我认为可能是我需要设置一个联合身份池,但阅读它似乎是用来提供 IAM 角色/外部用户的权限,我不想。

我怎么能做到这一点?

dan*_*nca 8

在深入研究之后,我找到了解决方案。总之,你应该:

  • 在 Cognito 上为预注册到 lambda 函数创建触发器
  • 这个 lambda 函数应该找到相应的帐户并链接两个用户
  • 从 lambda 函数返回事件

您可以从 Amplify cli 创建触发器,运行amplify auth update,执行“演练所有身份验证配置”,最后,它会询问您是否要创建触发器,确认并选择预注册触发器

然后编辑创建的函数文件,默认运行时是nodejs,我已经改成Python

这是我正在使用的代码

import boto3

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


def handler(event, context):
    print("Event: ", event)
    email = event['request']['userAttributes']['email']

    # Find a user with the same email
    response = client.list_users(
        UserPoolId=event['userPoolId'],
        AttributesToGet=[
            'email',
        ],
        Filter='email = "{}"'.format(email)
    )

    print('Users found: ', response['Users'])

    for user in response['Users']:
        provider = None
        provider_value = None
        # Check which provider it is using
        if event['userName'].startswith('Facebook_'):
            provider = 'Facebook'
            provider_value = event['userName'].split('_')[1]
        elif event['userName'].startswith('Google_'):
            provider = 'Google'
            provider_value = event['userName'].split('_')[1]

        print('Linking accounts from Email {} with provider {}: '.format(
            email,
            provider_value
        ))

        # If the signup is coming from a social provider, link the accounts
        # with admin_link_provider_for_user function
        if provider and provider_value:
            print('> Linking user: ', user)
            print('> Provider Id: ', provider_value)
            response = client.admin_link_provider_for_user(
                UserPoolId=event['userPoolId'],
                DestinationUser={
                    'ProviderName': 'Cognito',
                    'ProviderAttributeValue': user['Username']
                },
                SourceUser={
                    'ProviderName': provider,
                    'ProviderAttributeName': 'Cognito_Subject',
                    'ProviderAttributeValue': provider_value
                }
            )
    # Return the event to continue the workflow
    return event
Run Code Online (Sandbox Code Playgroud)

  • 是否处理使用社交媒体然后使用电子邮件/密码创建用户的情况示例:Facebook->Google->电子邮件/密码 (3认同)