Firestore + AngularFire - Link 个帐户
Firestore + AngularFire - Link accounts
我想为用户提供多种登录选项。目前 Google 和 Facebook。
但是,当用户使用 Google 登录并稍后尝试使用 Facebook 登录时,出现错误:
An account already exists with the same email address but different
sign-in credentials. Sign in using a provider associated with this
email address.
所以我必须 link 帐户。除了 this which didn't help much. The best info I could find is here on 之外,我没有找到任何相关文档,但出于某种原因,这对我来说还不够。
该解决方案处理 signInWithPopup
这给了我这个错误:
"Unable to establish a connection with the popup. It may have been
blocked by the browser."
So if the popup doesn't work, I call 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 登录并因为这个错误而被提示使用 Google 登录?我不想每次都合并凭据。但这是一个较小的问题。但我也很想在这里解决这个问题。 )
但是 signInWithCredential
给我这个错误:
linkWithCredential failed: First argument "credential" must be a valid
credential.
我找到了 "solution" here:
When calling signInWithCredential
with a access token you need to call
it like this:
signInWithCredential(null, token);
If you are doing
signInWithCredential(token)
then you need to use an ID Token rather
than an access token.
两个版本我都试过了,都没有成功。第二个版本:
this.afAuth.auth.signInWithCredential(firebase.auth.GoogleAuthProvider.credential((<any>this.credential).idToken))
类型转换是因为我猜类型定义有问题。
我尝试插入整个 credentials
对象,idToken
作为第一个参数,accessToken
作为第二个参数。但我总是得到:
第一个参数 "credential" 必须是有效的凭据。
当我写这篇文章时,我突然想到这可能是 linkWithCredential
而不是 signInWithCredential
方法的问题。根据错误消息,这应该是显而易见的。我只是没有注意到它,因为 google 搜索错误给了我那个解决方案。所以我很快检查了 authError
变量中的内容。有 accessToken
、providerId
和 signInMethod
方法。没有tokenId
。所以我尝试发送 accessToken
作为参数,而不是整个对象,但没有帮助。我试图将其发送为 null, accessToken
。没有帮助。我试图找到 linkWithCredential
方法的文档,但没有任何运气。所以我不知道它在期待什么。
我已经在这上面浪费了四天时间。这让我付出了很大的心理健康代价。有人可以帮我吗?
您可以存储基础 OAuth 凭据(id 令牌或访问令牌):error.credential.idToken
或 error.credential.accessToken
及其提供者 ID error.credential.providerId
。在 return 页面上,您可以重新初始化凭据,例如:firebase.auth.FacebookAuthProvider.credential(accessToken)
。使用 Google、link 凭据
成功重定向登录后
我想为用户提供多种登录选项。目前 Google 和 Facebook。 但是,当用户使用 Google 登录并稍后尝试使用 Facebook 登录时,出现错误:
An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address.
所以我必须 link 帐户。除了 this which didn't help much. The best info I could find is here on signInWithPopup
这给了我这个错误:
"Unable to establish a connection with the popup. It may have been blocked by the browser." So if the popup doesn't work, I call 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 登录并因为这个错误而被提示使用 Google 登录?我不想每次都合并凭据。但这是一个较小的问题。但我也很想在这里解决这个问题。 )
但是 signInWithCredential
给我这个错误:
linkWithCredential failed: First argument "credential" must be a valid credential.
我找到了 "solution" here:
When calling
signInWithCredential
with a access token you need to call it like this:
signInWithCredential(null, token);
If you are doingsignInWithCredential(token)
then you need to use an ID Token rather than an access token.
两个版本我都试过了,都没有成功。第二个版本:
this.afAuth.auth.signInWithCredential(firebase.auth.GoogleAuthProvider.credential((<any>this.credential).idToken))
类型转换是因为我猜类型定义有问题。
我尝试插入整个 credentials
对象,idToken
作为第一个参数,accessToken
作为第二个参数。但我总是得到:
第一个参数 "credential" 必须是有效的凭据。
当我写这篇文章时,我突然想到这可能是 linkWithCredential
而不是 signInWithCredential
方法的问题。根据错误消息,这应该是显而易见的。我只是没有注意到它,因为 google 搜索错误给了我那个解决方案。所以我很快检查了 authError
变量中的内容。有 accessToken
、providerId
和 signInMethod
方法。没有tokenId
。所以我尝试发送 accessToken
作为参数,而不是整个对象,但没有帮助。我试图将其发送为 null, accessToken
。没有帮助。我试图找到 linkWithCredential
方法的文档,但没有任何运气。所以我不知道它在期待什么。
我已经在这上面浪费了四天时间。这让我付出了很大的心理健康代价。有人可以帮我吗?
您可以存储基础 OAuth 凭据(id 令牌或访问令牌):error.credential.idToken
或 error.credential.accessToken
及其提供者 ID error.credential.providerId
。在 return 页面上,您可以重新初始化凭据,例如:firebase.auth.FacebookAuthProvider.credential(accessToken)
。使用 Google、link 凭据