Firestore + AngularFire - Ссылка аккаунтов - PullRequest
0 голосов
/ 06 мая 2018

Я хочу предоставить пользователю несколько вариантов входа. На данный момент Google и Facebook. Но когда пользователь входит в систему с помощью Google, а затем пытается войти через Facebook, я получаю сообщение об ошибке:

Учетная запись уже существует с тем же адресом электронной почты, но с другим учетные данные для входа. Войдите с помощью провайдера, связанного с этим адрес электронной почты.

Так что я должен связать учетные записи. Я не нашел соответствующей документации, за исключением этого , который не сильно помог. Лучшая информация, которую я смог найти, здесь: stackoverflow , но по какой-то причине мне этого было недостаточно. Решение имеет дело с signInWithPopup, что дает мне эту ошибку:

"Невозможно установить соединение с всплывающим окном. Возможно, это было заблокирован браузером. " Поэтому, если всплывающее окно не работает, я вызываю signInWithRedirect:

private authLoginWithPopup(provider: AuthProvider) {
  this.afAuth.auth.signInWithPopup(provider)
    .then((result) => {
      this.credential = result.credential;
      this.updateUserData(result);
    })
    .catch(error => {
      if (error.code === 'auth/account-exists-with-different-credential') {
        this.mergeCredentials(error);
      } else if (error.code === 'auth/popup-blocked') {
        this.authLoginWithRedirect(new firebase.auth.GoogleAuthProvider());
      }
    });
}

После всплывающего окна вы заходите в then и можете делать что угодно. Но после перенаправления вы теряете свою информацию. Поэтому я сохранил его в localStorage:

this.afAuth.auth.fetchProvidersForEmail(error.email).then(providers => {
  const [ provider ] = providers;
  if (provider === 'google.com') {
    const googleProvider = new firebase.auth.GoogleAuthProvider();
    googleProvider.setCustomParameters({ login_hint: error.email });
    localStorage.setItem('auth_error', JSON.stringify(error.credential));
    this.authLoginWithPopup(googleProvider);
  }
});

И я получаю его в getRedirectResult:

constructor(
  private afAuth: AngularFireAuth,
  private afs: AngularFirestore,
) {
  this.afAuth.auth.getRedirectResult().then(result => {
    if (result.user) {
      this.credential = result.credential;
      const authError = JSON.parse(localStorage.getItem('auth_error'));

      if (authError) {
        localStorage.removeItem('auth_error');

        this.afAuth.auth.signInWithCredential(
          firebase.auth.GoogleAuthProvider.credential(
            null, (<any>this.credential).accessToken
          )
        )
          .then(user => {
            user.linkWithCredential(authError)
          })
          .catch(error => {
            console.log('error', error);
          });
      }
    }
  });
}

(Это создает другую проблему. Как я могу узнать, был ли это обычный signInWithRedirect пользователем, который выполнил вход в Google напрямую. Или это было перенаправление после того, как пользователь попытался войти в систему с Facebook и получил запрос на Выполните вход в Google из-за этой ошибки. Я не хочу объединять учетные данные каждый раз. Но это меньшая проблема. Но я хотел бы найти решение этой проблемы также.)

Но signInWithCredential дает мне эту ошибку:

linkWithCredential fail: первый аргумент "credential" должен быть действительным удостоверение.

Для которого я нашел "решение" здесь :

При звонке signInWithCredential с токеном доступа необходимо позвонить это так:

signInWithCredential(null, token); Если вы делаете signInWithCredential(token) тогда вам нужно использовать идентификационный токен, а не чем токен доступа.

Я пробовал обе версии, обе безуспешно . Вторая версия: this.afAuth.auth.signInWithCredential(firebase.auth.GoogleAuthProvider.credential((<any>this.credential).idToken)) Преобразование типов происходит потому, что в определениях типов есть проблема.

Я попытался вставить целый объект credentials, idToken в качестве первого параметра, accessToken в качестве второго параметра. Но я всегда получаю: Первый аргумент «учетные данные» должен быть действительным учетным данными.

Когда я писал это, мне пришло в голову, что это, вероятно, проблема с linkWithCredential, а не с signInWithCredential методом. Что должно быть очевидно на основании сообщения об ошибке. Я просто не заметил этого, потому что поиск в Google дал мне это решение. Поэтому я быстро проверил, что находится в переменной authError. Существует метод accessToken, providerId и signInMethod. Там нет tokenId. Поэтому я попытался отправить accessToken в качестве параметра вместо целого объекта, и это не помогло. Я пытался отправить его как null, accessToken. Не помогло Я попытался найти документацию для метода linkWithCredential, но безуспешно. Так что я не знаю, чего он ожидает.

Я уже потратил четыре дня на это. Это стоило мне много моего психического здоровья. Может кто-нибудь помочь мне, пожалуйста?

1 Ответ

0 голосов
/ 09 мая 2018

Можно сохранить базовые учетные данные OAuth (идентификатор токена или токен доступа): error.credential.idToken или error.credential.accessToken и идентификатор его провайдера, error.credential.providerId. По возвращении на страницу вы можете повторно инициализировать учетные данные, например: firebase.auth.FacebookAuthProvider.credential(accessToken). После успешного входа в Google с помощью перенаправления введите учетные данные

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...