Как завершить вход в систему только после завершения functions.auth.user (). OnCreate - PullRequest
0 голосов
/ 31 января 2020

Я использую функции Firebase, и у меня есть функция, которая добавляет новую коллекцию, когда пользователь создает. Иногда проблема заключается в том, что пользователь вошел в систему до выполнения функции, поэтому пользователь вошел в систему, но новая коллекция еще не создана (а затем у меня появляется сообщение об ошибке «Отсутствует или недостаточно разрешений. Потому что правило не может найти эту коллекцию»). Как я могу справиться с этим?

Возможно ли завершить sh вход в систему пользователя (например, с помощью провайдера Google) только тогда, когда все элементы из

export const createCollection = functions.auth.user().onCreate(async user => {
  try {
    const addLanguages = await addFirst();
    const addSecondCollection = await addSecond();

    async function addFirst() {
      const userRef = admin.firestore().doc(`languages/${user.uid}`);
      await userRef.set(
        {
          language: null
        },
        { merge: true }
      );

      return 'done';
    }

    async function addSecond() {
      // ...
    }

    return await Promise.all([addLanguages, addSecondCollection]);
  } catch (error) {
    throw new functions.https.HttpsError('unknown', error);
  }
});

закончены? Значит окно провайдера гугл закрыто и пользователь залогинен только после этого? (и не использовать setTimeouts et c)

1 Ответ

3 голосов
/ 31 января 2020

AFAIK невозможно напрямую связать два процесса, подразумеваемых в вашем приложении:

  • С одной стороны, у вас реализован поток входа в Google в ваш пользовательский интерфейс (даже если во внутреннем интерфейсе есть вызов службы аутентификации) и;
  • С другой стороны, у вас есть облачная функция, которая выполняется в back-end .

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

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

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

firebase.auth().signInWithPopup(provider)
.then(function(result) {
  var token = result.credential.accessToken;
  var user = result.user;  
  //Here we know the userId then we can set a listener to the doc languages/${user.uid}

  firebase.firestore().collection("languages").doc(user.uid)
    .onSnapshot(function(doc) {
       if(doc.exists) {
         console.log("Current data: ", doc.data());
         //Do whatever you want with the user doc
       } else  {
         console.log("Language document not yet created by the Cloud Function");
       }

    });
}).catch(function(error) {
  var errorCode = error.code;
  var errorMessage = error.message;
  var email = error.email;
  var credential = error.credential;
  // ...
});

Как сказано выше, в приведенном выше коде мы учитываем только первый документ Firestore, созданный функцией addFirst(). Но вам, вероятно, нужно дождаться создания двух документов, прежде чем читать их из внешнего интерфейса.

Итак, вы можете изменить свой CF следующим образом:

export const createCollection = functions.auth.user().onCreate(async user => {
  try {
    await addFirst();
    await addSecond();
    return null;

    async function addFirst() {
      const userRef = admin.firestore().doc(`languages/${user.uid}`);
      await userRef.set(
        {
          language: null
        },
        { merge: true }
      );
    }

    async function addSecond() {
      // ...
    }

  } catch (error) {
    console.log(error);
    return null;
  }
});

Обратите внимание, что вы не нужно использовать Promise.all(): следующие две строки уже выполняют две записи документа в Firestore. И, поскольку вы используете async/await, второй документ пишется только после того, как написан первый.

    const addLanguages = await addFirst();
    const addSecondCollection = await addSecond();

Так что вам просто нужно установить слушателя на путь второго документа, и все готово !


Наконец, обратите внимание, что выполнение

throw new functions.https.HttpsError('unknown', error);

в вашем блоке catch - это способ обработки ошибок для функции Callable Cloud. Здесь вы пишете фоновую функцию Cloud, и вы можете просто использовать return null;

...