AWS Amplify:如何为基于电子邮件的身份验证映射社交提供商属性?
AWS Amplify: How to map social providers attributes for an email based authentication?
我有一个使用 AWS Amplify 构建的 React Web 应用程序
我已经使用 Cognito 用户池添加了身份验证,我没有使用用户名,我选择了仅使用 email/phone 的登录名,我不需要用户名,但 Cognito 无论如何都会创建一个随机用户名。
我希望用户使用他们的电子邮件或使用一个社交提供商(Facebook 或 Google)登录,没关系,根据电子邮件,他们应该可以访问同一帐户。
我认为这是很正常的做法。
但是,当我第一次尝试使用社交服务提供商登录时,我注意到 Cognito 没有给我相同的帐户,而是创建了一个新帐户,具有不同的用户名,并且 EXTERNAL_PROVIDER 作为用户池中的帐户状态
所以,我认为这可能只是一些映射不正确,我去了联合部分的属性映射,我看到 Facebook Id 和 Google Sub 被分配给了用户名,我试图删除它,令我惊讶的是,它被分配回了用户名。
然后我想"I can just create a custom attribute to store that information and it should be fine".
所以我这样做了,为 Facebook 创建了一个属性,为 GoogleId 创建了一个属性...再次尝试...不,仍然返回到用户名,但没有错误消息,什么都没有...
我寻求有关文档的帮助并找到了 this
Currently, only the Facebook id, Google sub, login with Amazon user_id, and Sign in with Apple sub attributes can be mapped to the Amazon Cognito User Pools username attribute.
如果这总是将每个提供者 ID 与用户名相关联,则无法合并这些帐户
我认为可能是我需要设置一个联合身份池,但阅读它似乎是用来向外部用户提供 IAM roles/permission,我不想这样做。
知道如何实现吗?
深入研究后,我找到了解决方案。
总之,您应该:
- 在 Cognito 上为预注册 lambda 函数创建触发器
- 这个 lambda 函数应该找到相应的帐户和 link 两个用户
- Return 来自 lambda 函数的事件
您可以从 Amplify cli 创建触发器,运行 amplify auth update
,执行 "Walkthrough all the auth configurations",最后,它会询问您是否要创建触发器,确认并 select 预注册触发器
然后编辑创建的函数文件,默认运行时间是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
我有一个使用 AWS Amplify 构建的 React Web 应用程序 我已经使用 Cognito 用户池添加了身份验证,我没有使用用户名,我选择了仅使用 email/phone 的登录名,我不需要用户名,但 Cognito 无论如何都会创建一个随机用户名。
我希望用户使用他们的电子邮件或使用一个社交提供商(Facebook 或 Google)登录,没关系,根据电子邮件,他们应该可以访问同一帐户。
我认为这是很正常的做法。 但是,当我第一次尝试使用社交服务提供商登录时,我注意到 Cognito 没有给我相同的帐户,而是创建了一个新帐户,具有不同的用户名,并且 EXTERNAL_PROVIDER 作为用户池中的帐户状态
所以,我认为这可能只是一些映射不正确,我去了联合部分的属性映射,我看到 Facebook Id 和 Google Sub 被分配给了用户名,我试图删除它,令我惊讶的是,它被分配回了用户名。 然后我想"I can just create a custom attribute to store that information and it should be fine".
所以我这样做了,为 Facebook 创建了一个属性,为 GoogleId 创建了一个属性...再次尝试...不,仍然返回到用户名,但没有错误消息,什么都没有...
我寻求有关文档的帮助并找到了 this
Currently, only the Facebook id, Google sub, login with Amazon user_id, and Sign in with Apple sub attributes can be mapped to the Amazon Cognito User Pools username attribute.
如果这总是将每个提供者 ID 与用户名相关联,则无法合并这些帐户 我认为可能是我需要设置一个联合身份池,但阅读它似乎是用来向外部用户提供 IAM roles/permission,我不想这样做。
知道如何实现吗?
深入研究后,我找到了解决方案。 总之,您应该:
- 在 Cognito 上为预注册 lambda 函数创建触发器
- 这个 lambda 函数应该找到相应的帐户和 link 两个用户
- Return 来自 lambda 函数的事件
您可以从 Amplify cli 创建触发器,运行 amplify auth update
,执行 "Walkthrough all the auth configurations",最后,它会询问您是否要创建触发器,确认并 select 预注册触发器
然后编辑创建的函数文件,默认运行时间是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