Я хочу предоставить пользователю несколько вариантов входа. На данный момент 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
, но безуспешно. Так что я не знаю, чего он ожидает.
Я уже потратил четыре дня на это. Это стоило мне много моего психического здоровья. Может кто-нибудь помочь мне, пожалуйста?