Сбой потока аутентификации Cognito: уже найдена запись для имени пользователя Facebook_10155611263153532

Цель состоит в том, чтобы реализовать поток аутентификации поставщика социальных сетей, как описано в Пулы пользователей. Интеграция приложений и федерация.

Одна важная вещь, которой я хочу удовлетворить, - это объединить учетные записи пула пользователей с одним и тем же адресом электронной почты.

Я добиваюсь этого, вызывая adminLinkProviderForUser внутри PreSignUp_ExternalProvider когнитивный лямбда-триггер.

Так что с этим все работает. Новый пользователь, предоставленный социальной сетью, регистрируется и связывается с уже существующим пользователем Cognito (пользователь + пароль).

Однако процесс аутентификации с точки зрения пользователя не завершен. Он терпит неудачу на последнем шаге, когда вызывается uri обратного вызова (определенный в пользовательском пуле когнито):

ошибка: invalid_request

error_description: Уже найдена запись для имени пользователя Facebook_10155611263152353

Но затем, если пользователь повторяет поток социальной аутентификации, все работает и получит токены сеанса, которые представляют исходного пользователя пула пользователей Cognito (того, у которого уже было это электронное письмо).

Обратите внимание, что я тестирую поток аутентификации на пустом пуле пользователей, без учетных записей пользователей.


person Daniel Birowsky Popeski    schedule 14.12.2017    source источник


Ответы (4)


Для всех бедняков, борющихся с этой проблемой еще в 2020 году, как и я:

  • В конце концов я решил проблему, поймав сообщение «Уже найдена запись для имени пользователя» в моем клиентском приложении и повторив весь процесс аутентификации еще раз.
  • Luckily the error only gets fired on the initial external provider signup but not in the subsequent signins of the same user (cause it happens during signup trigger, duh). I'm taking a wild guess, but here is what I think is happening:
    • In my case, the facebook provider was getting succesfully linked with the pre-existing cognito email/password user. new Facebook userpool entry linking to the email/password user was succesfully created.
    • Тем не менее, похоже, что cognito попытался зарегистрировать полностью изолированного пользователя Facebook_id во время внутреннего процесса регистрации (даже несмотря на то, что на предыдущем шаге уже была создана ссылка пользователя с тем же именем пользователя). Поскольку «связующий пользователя» с именем пользователя Facebook_id уже существовал, когнито выдало внутреннюю ошибку «Уже найдена запись для ошибки имени пользователя Facebook_id».
    • Эта ошибка неоднократно озвучивалась разработчиками AWS с 2017 года, и есть даже некоторые ответы, в которых они работают, но в 2020 году она все еще не исправлена.
person furyozo    schedule 13.03.2020
comment
Не могли бы вы поделиться дополнительной информацией о том, как еще раз повторить весь процесс аутентификации? Вы используете Amplify на веб-интерфейсе? Я попытался повторить весь процесс аутентификации, но он продолжает перенаправлять и добавлять code = random_string & state = random_string к моему предустановленному URL-адресу перенаправления когнито. - person Jun711; 25.04.2020
comment
Я использую усиление. Я предполагаю, что вы используете какую-то форму аутентификации, чтобы ваши пользователи регистрировались / входили в ваше приложение. Повторяя весь процесс аутентификации, я имею в виду повторение процесса вызова службы регистрации / входа в систему социального провайдера еще раз после того, как ваш пользователь уже зарегистрировался в вашем приложении, поэтому ваш поток будет выглядеть следующим образом: 1. ваш пользователь регистрируется через facebook, так как он не зарегистрировался в вашем приложении до 2. вы получаете сообщение об ошибке во время регистрации 3. вы обнаруживаете ошибку в клиенте, анализируя URL-адрес обратного вызова 4. вы вызываете вход еще раз - person furyozo; 14.05.2020
comment
Как вы делаете привязку, описанную в facebook, когда провайдер успешно связывается с уже существующим пользователем когнитивной электронной почты / паролем? - person devth; 16.05.2020
comment
@devth есть два варианта использования, которые следует учитывать: 1. пользователь уже был зарегистрирован по электронной почте / паролю 2. пользователь использует социального провайдера для своей первой регистрации. Сначала я проверяю, существует ли уже данный пользователь, используя метод AWS.CognitoIdentityServiceProvider() listUsers, если он это делает I используйте метод AWS.CognitoIdentityServiceProvider() adminLinkProviderForUser, чтобы связать их вместе - person furyozo; 18.05.2020
comment
@furyozo, как вы справляетесь с тем, что пользователю нужно дважды пройти аутентификацию у поставщика социальных сетей? У меня та же проблема и решение, но мои пользователи дважды видят всплывающее окно SignInWithApple. Довольно плохой UX. - person tvb; 04.06.2020
comment
@Tristan В настоящее время у меня такая же проблема со входом в систему Apple, и это текущая настройка, которую я использую, чтобы мои приложения оставались в магазине Apple. Я планирую начать экспериментировать с использованием триггера когнитивной аутентификации Post, чтобы связать строку электронной почты и социального провайдера вместе, но я еще не дошел до этого. Гипотеза заключается в том, что если вы подключаете уже существующие строки пользователей когнитивных данных (одну для регистрации по электронной почте, а другую для вашей федерации), она может связать их вместе, не создавая новую строку. Это полностью исправит уже найденную запись об ошибке имени пользователя. - person furyozo; 06.06.2020
comment
Та же проблема и с SAML. Я хотел связать уже существующего пользователя с SAML. К счастью, для меня нет ничего страшного в том, чтобы их не связывать, но это наверняка неожиданно. - person mrgoos; 26.06.2020
comment
@furyozo есть ли удача с гипотезой о триггере авторизации поста? - person Lerman; 01.07.2020
comment
@furyozo Вызов Auth.federatedSignIn({provider: 'Google'}) дважды работает для Google, но не для SignInWithApple. Я пробовал Post authentication cognito trigger to link the email and social provider row together раньше, у меня это не сработало, так как ссылка может быть сделана только до создания учетной записи EXTERNAL_PROVIDER. Вы нашли другой путь? - person Jun711; 30.07.2020
comment
@ Jun711 Я сталкиваюсь с теми же проблемами со всеми поставщиками, кроме Google. Есть ли кто-нибудь с контрактом на поддержку AWS (у меня его пока нет), который готов снова ткнуть AWS в эту проблему? - person tvb; 07.08.2020
comment
@tvb Если вы используете Amplify, вы можете зарегистрировать проблему на их GitHub github.com/aws-amplify / ampify-js - person Jun711; 07.08.2020
comment
@ Jun711 К сожалению, я не использую Amplify. - person tvb; 08.08.2020
comment
@tvb Вы можете найти аналогичную проблему на дискуссионном форуме AWS или открыть проблему, если ее нет forum.aws.amazon.com/forum.jspa?forumID=173 - person Jun711; 09.08.2020
comment
Столкнулся с той же проблемой, даже не уверен, стоит ли использовать когнито. Эта услуга потратила больше времени, чем сэкономила. Расстроенный. Поистине разочарован. - person Yash Kalwani; 12.04.2021

Да, это то, как это в настоящее время настроено. Если вы попытаетесь связать пользователей с помощью триггера PreSignUp, первый раз не сработает. Лучшим способом справиться с этим (я думаю) было бы предоставить в вашем пользовательском интерфейсе возможность связывать внешние учетные записи при входе в систему. В триггере предварительной регистрации найдите пользователя с таким же уникальным атрибутом (например, адрес электронной почты) и посмотрите, была ли регистрация от внешнего поставщика. Затем покажите сообщение, например, электронная почта уже существует. Войдите в систему и используйте это меню / параметр для ссылки. Однако не тестировал это.

person agent420    schedule 18.12.2017
comment
Это плохой UX. Если пользователь входит в систему с другим провайдером (возможно, они забыли, какой из них изначально использовали), он должен автоматически установить связь. - person devth; 18.05.2020

Чтобы уточнить ответ @ 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);
};

person Darbio    schedule 22.12.2019

Тот же код в JavaScript был вызван getUser вместо listUsers. Также предполагается, что у всех пользователей в качестве имени пользователя указан идентификатор электронной почты.

const aws = require('aws-sdk');

exports.handler = async (event, context, callback) => {
    console.log("event" + JSON.stringify(event));
    const cognitoidentityserviceprovider = new aws.CognitoIdentityServiceProvider({apiVersion: '2016-04-18'});
    const emailId = event.request.userAttributes.email
    const userName = event.userName
    const userPoolId = event.userPoolId
    var params = {
        UserPoolId: userPoolId,
        Username: userName
    };
    var createUserParams = {
        UserPoolId: userPoolId,
        Username: emailId,
        UserAttributes: [
            {
                Name: "email",
                Value: emailId
            },
        ],
        TemporaryPassword: "xxxxxxxxx"
    };

    var googleUserNameSplitArr = userName.split("_");
    var adminLinkUserParams = {
        DestinationUser: {
            ProviderAttributeName: 'UserName',
            ProviderAttributeValue: emailId,
            ProviderName: "Cognito"
        },
        SourceUser: {
            ProviderAttributeName: "Cognito_Subject",
            ProviderAttributeValue: googleUserNameSplitArr[1],
            ProviderName: 'Google'
        },
        UserPoolId: userPoolId
    };

    var addUserToGroupParams = {
        GroupName: "Student",
        UserPoolId: userPoolId,
        Username: emailId
    };

    if (userName.startsWith("Google_")) {
        await cognitoidentityserviceprovider.adminGetUser(params, function (err, data) {
            if (err) {
                console.log("No user present")
                console.log(err, err.stack);
                cognitoidentityserviceprovider.adminCreateUser(createUserParams, function (err, data) {
                    if (err) console.log(err, err.stack);
                    else {
                        console.log("User Created ")
                        cognitoidentityserviceprovider.adminAddUserToGroup(addUserToGroupParams, function (err, data) {
                            if (err) console.log(err, err.stack);
                            else {

                                console.log("added user to group");
                                console.log(data);
                            }
                        });
                        cognitoidentityserviceprovider.adminLinkProviderForUser(adminLinkUserParams, function (err, data) {
                            if (err) console.log(err, err.stack);
                            else {
                                console.log("user linked");
                                console.log(data);
                            }
                        });
                        console.log(data);
                    }
                });
            } else {
                console.log("user already present")
                cognitoidentityserviceprovider.adminLinkProviderForUser(adminLinkUserParams, function (err, data) {
                    if (err) console.log(err, err.stack); // an error occurred
                    else {
                        console.log("userlinked since user already existed");
                        console.log(data);
                    }
                });
                console.log(data);
            }
        });
    }
    console.log("after the function custom");
    callback(null, event);
};
person aashwin malik    schedule 10.09.2020