我想为用户提供多种登录选项。目前谷歌和Facebook。 但是,当用户登录Google并稍后尝试使用Facebook登录时,我收到错误消息:
帐户已存在且电子邮件地址相同但不同 登录凭据。使用与此关联的提供商登录 电子邮件地址。
所以我必须链接帐户。我没有找到任何相关的文档,除了this没有多大帮助。我能找到的最好的信息是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());
}
});
}
在Popup之后,你会进入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);
});
}
}
});
}
(这会产生另一个问题。如何直接通过Google登录的用户知道它是否是正常的signInWithRedirect。或者,如果用户尝试使用Facebook登录并且提示我因为这个错误而登录谷歌?我不想每次合并凭证。但这是一个较小的问题。但我也很乐意在这里解决这个问题。)
但是signInWithCredential
给了我这个错误:
linkWithCredential失败:第一个参数“credential”必须是有效的 凭证。
我找到了“解决方案”here:
使用访问令牌呼叫
signInWithCredential
时,您需要致电 它是这样的:
signInWithCredential(null, token);
如果你这样做的话signInWithCredential(token)
然后您需要使用ID令牌 而不是访问令牌。
我尝试了两个版本,但均未成功。第二个版本:
this.afAuth.auth.signInWithCredential(firebase.auth.GoogleAuthProvider.credential((<any>this.credential).idToken))
类型转换是存在的,因为我猜测类型定义存在问题。
我尝试插入整个credentials
对象,idToken
作为第一个参数,accessToken
作为第二个参数。但我总是得到:
第一个参数“凭证”必须是有效的凭证。
当我写这篇文章时,我突然意识到它可能与linkWithCredential
有关,而不是signInWithCredential
方法。根据错误消息,这应该是显而易见的。我只是没有注意到它,因为谷歌搜索错误给了我解决方案。所以我快速检查了authError
变量中的内容。有accessToken
,providerId
和signInMethod
方法。没有tokenId
。所以我尝试发送accessToken
作为参数,而不是整个对象,它没有帮助。我试图将其作为null, accessToken
发送。没有帮助。我试图找到linkWithCredential
方法的文档,没有任何运气。所以我不知道它的期望是什么。
我已经浪费了四天时间。这让我的心理健康付出了很大的代价。有人能帮帮我吗?
答案 0 :(得分:1)
您可以存储基础OAuth凭据(ID令牌或访问令牌):error.credential.idToken
或error.credential.accessToken
及其提供商ID error.credential.providerId
。返回页面后,您可以重新初始化凭据,例如:firebase.auth.FacebookAuthProvider.credential(accessToken)
。成功重定向登录Google后,请链接该凭据