Как связать родного пользователя AWS Cognito с федеративным пользователем

#amazon-cognito #federated-identity

#amazon-cognito #федеративная идентификация

Вопрос:

В настоящее время Cognito позволяет объединять федеративных пользователей (пользователей, регистрирующихся у внешних поставщиков удостоверений, например Google ) с собственными пользователями (пользователями, которые зарегистрировались с помощью комбинации имени пользователя и пароля).

Есть ли способ объединить существующего федеративного пользователя с новым родным пользователем?

Ответ №1:

Нет. Вы можете создать ссылку только от пользователя, который никогда не входил в систему. То есть вы можете связать нового пользователя только в момент его создания (в триггере предварительной авторизации).

«Это позволяет создать ссылку из существующей учетной записи пользователя на внешнее федеративное удостоверение пользователя, которое еще не использовалось для входа».

Лично я улавливаю этот случай в триггере предварительной регистрации и отклоняю регистрацию с помощью пользовательского сообщения («Учетная запись с этим адресом электронной почты уже существует, пожалуйста, войдите в систему с помощью Google»).

Вот моя предварительная регистрация lambda на случай, если вы сочтете ее полезной

 const AWS = require("aws-sdk");
const cognito = new AWS.CognitoIdentityServiceProvider();

exports.handler = (event, context, callback) => {

  function checkForExistingUsers(event, linkToExistingUser) {

    console.log("Executing checkForExistingUsers");

    var params = {
      UserPoolId: event.userPoolId,
      AttributesToGet: ['sub', 'email'],
      Filter: "email = ""   event.request.userAttributes.email   """
    };

    return new Promise((resolve, reject) =>
      cognito.listUsers(params, (err, result) => {
        if (err) {
          reject(err);
          return;
        }
        if (result amp;amp; result.Users amp;amp; result.Users[0] amp;amp; result.Users[0].Username amp;amp; linkToExistingUser) {
          console.log("Found existing users: ", result.Users);
          if (result.Users.length > 1){
            result.Users.sort((a, b) => (a.UserCreateDate > b.UserCreateDate) ? 1 : -1);
            console.log("Found more than one existing users. Ordered by createdDate: ", result.Users);
          }
          linkUser(result.Users[0].Username, event).then(result => {
              resolve(result);
            })
            .catch(error => {
              reject(err);
              return;
            });
        } else {
          resolve(result);
        }

      })
    );

  }

  function linkUser(sub, event) {
    console.log("Linking user accounts with target sub: "   sub   "and event: ", event);

    //By default, assume the existing account is a Cognito username/password
    var destinationProvider = "Cognito";
    var destinationSub = sub;
    //If the existing user is in fact an external user (Xero etc), override the the provider
    if (sub.includes("_")) {
      destinationProvider = sub.split("_")[0];
      destinationSub = sub.split("_")[1];
    }
    var params = {
      DestinationUser: {
        ProviderAttributeValue: destinationSub,
        ProviderName: destinationProvider
      },
      SourceUser: {
        ProviderAttributeName: 'Cognito_Subject',
        ProviderAttributeValue: event.userName.split("_")[1],
        ProviderName: event.userName.split("_")[0]
      },
      UserPoolId: event.userPoolId
    };
    console.log("Parameters for adminLinkProviderForUser: ", params);
    return new Promise((resolve, reject) =>
      cognito.adminLinkProviderForUser(params, (err, result) => {
        if (err) {
          console.log("Error encountered whilst linking users: ", err);
          reject(err);
          return;
        }
        console.log("Successfully linked users.");
        resolve(result);
      })
    );
  }

  console.log(JSON.stringify(event));

  if (event.triggerSource == "PreSignUp_SignUp" || event.triggerSource == "PreSignUp_AdminCreateUser") {

    checkForExistingUsers(event, false).then(result => {
        if (result != null amp;amp; result.Users != null amp;amp; result.Users[0] != null) {
          console.log("Found at least one existing account with that email address: ", result);
          console.log("Rejecting sign-up");
          //prevent sign-up
          callback("An external provider account alreadys exists for that email address", null);
        } else {
          //proceed with sign-up
          callback(null, event);
        }
      })
      .catch(error => {
        console.log("Error checking for existing users: ", error);
        //proceed with sign-up
        callback(null, event);
      });

  }

  if (event.triggerSource == "PreSignUp_ExternalProvider") {

    checkForExistingUsers(event, true).then(result => {
        console.log("Completed looking up users and linking them: ", result);
        callback(null, event);
      })
      .catch(error => {
        console.log("Error checking for existing users: ", error);
        //proceed with sign-up
        callback(null, event);
      });

  }

};