问题
When signing in a user with the same email address through the Google and Facebook identity providers, AWS Cognito creates multiple entries in the user pool, one entry per identity provider used:
I have used the example code provided in this tutorial to set up AWS Cognito: The Complete Guide to User Authentication with the Amplify Framework
- How can I create just one user instead of multiple users?
- Is it possible to have AWS Cognito automatically combine (federate) the entries from multiple providers into one entry or should AWS Lambda functions be used to accomplish this?
回答1:
Yes. You can do it by using AdminLinkProviderForUser https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminLinkProviderForUser.html
The idea is:
- In PreSignUp lambda hook, we Link Provider to User if User already signed up. E.g:
import CognitoIdentityServiceProvider from 'aws-sdk/clients/cognitoidentityserviceprovider'
const cognitoIdp = new CognitoIdentityServiceProvider()
const getUserByEmail = async (userPoolId, email) => {
const params = {
UserPoolId: userPoolId,
Filter: `email = "${email}"`
}
return cognitoIdp.listUsers(params).promise()
}
const linkProviderToUser = async (username, userPoolId, providerName, providerUserId) => {
const params = {
DestinationUser: {
ProviderAttributeValue: username,
ProviderName: 'Cognito'
},
SourceUser: {
ProviderAttributeName: 'Cognito_Subject',
ProviderAttributeValue: providerUserId,
ProviderName: providerName
},
UserPoolId: userPoolId
}
const result = await (new Promise((resolve, reject) => {
cognitoIdp.adminLinkProviderForUser(params, (err, data) => {
if (err) {
reject(err)
return
}
resolve(data)
})
}))
return result
}
exports.handler = async (event, context, callback) => {
if (event.triggerSource === 'PreSignUp_ExternalProvider') {
const userRs = await getUserByEmail(event.userPoolId, event.request.userAttributes.email)
if (userRs && userRs.Users.length > 0) {
const [ providerName, providerUserId ] = event.userName.split('_') // event userName example: "Facebook_12324325436"
await linkProviderToUser(userRs.Users[0].Username, event.userPoolId, providerName, providerUserId)
} else {
console.log('user not found, skip.')
}
}
return callback(null, event)
}
- Then when user use OAuth with Facebook/Google with User Pool, the Pool will return this User linked.
Note: You may see 2 records in User Pool UI, but when access User record detail, They already merged.
来源:https://stackoverflow.com/questions/59635482/aws-cognito-best-practice-to-handle-same-user-with-same-email-address-signing