目标是实现社交提供程序身份验证流,如用户池应用集成和联合中所述。
一件重要的事情,我想满足,是合并用户池帐户,有相同的电子邮件地址。
我通过调用adminLinkProviderForUser内PreSignUp_ExternalProvider认知lambda触发器来实现这一点。
所以有了这个,一切都正常了。新的社交提供用户正在注册并与已经存在的Cognito(用户通行证)用户链接。
但是,从用户的角度来看,身份验证流不会完成。它在调用回调 uri(在 cognito 用户池中定义)的最后一步失败:
错误:invalid_request
error_description:已找到用户名条目Facebook_10155611263152353
但是,如果用户重试社交身份验证流程,一切正常,并将获得代表原始Cognito用户池用户(已经拥有该电子邮件的用户)的会话令牌。
注意,我正在一个空用户池上测试身份验证流,没有用户帐户。
对于所有在 2020 年仍然以同样的方式与这个问题作斗争的可怜灵魂:
是的,这就是它目前的设置方式。如果您尝试使用预注册触发器链接用户,则第一次将不起作用。处理此问题的更好方法(我认为)是在 UI 中提供一个选项,以便在登录时链接外部帐户。在预注册触发器中,搜索具有相同唯一属性(例如电子邮件)的用户,并查看注册是否来自外部提供商。然后显示一条消息,例如电子邮件已存在。登录
详细说一下@agent420的回答,这是我目前在用的(Typescript示例)。
当社交身份尝试注册并且电子邮件地址已经存在时,我使用PreSignUp
触发器捕捉到这一点,然后向用户返回错误消息。在应用程序内部,在用户的配置文件页面上,有一个选项可以链接一个身份提供者,该提供者调用adminLinkProviderForUser
API。
import {
Context,
CognitoUserPoolTriggerEvent,
CognitoUserPoolTriggerHandler,
} from 'aws-lambda';
import * as aws from 'aws-sdk';
import { noTryAsync } from 'no-try';
export const handle: CognitoUserPoolTriggerHandler = async (
event: CognitoUserPoolTriggerEvent,
context: Context,
callback: (err, event: CognitoUserPoolTriggerEvent) => void,
): Promise<any> => {
context.callbackWaitsForEmptyEventLoop = false;
const { email } = event.request.userAttributes;
// pre sign up with external provider
if (event.triggerSource === 'PreSignUp_ExternalProvider') {
// check if a user with the email address already exists
const sp = new aws.CognitoIdentityServiceProvider();
const { error } = await noTryAsync(() =>
sp
.adminGetUser({
UserPoolId: 'your-user-pool-id',
Username: email,
})
.promise(),
);
if (error && !(error instanceof aws.AWSError)) {
throw error;
} else if (error instanceof aws.AWSError && error.code !== 'UserNotFoundException') {
throw error;
}
}
callback(null, event);
};