Firebase有一种奇怪的情况,当有人首先使用google provider进行登录时,您将无法使用其他提供商登录,就像您在问题Firebase JS API auth - account-exists-with-different-credential中看到的那样。
最后,我在上述问题的2个第一答案之后实现了这一目标,但是有1个问题和1个改进。
问题是,为什么当我使用异步内部catchError时,它期望一个正常的动作而不是一个可观察的动作。
改进之处在于,当我调用弹出窗口时,是否可以隐藏它?还是避免再次调用SigninProvider操作?(原因是因为用户将看到2个弹出窗口)。
const resultProvider = await this.afAuth.auth.signInWithPopup(linkedProvider);
await resultProvider.user.linkWithCredential(error.credential);
全效果
@Effect()
signInProvider: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.SIGNIN_PROVIDER),
map((action: SigninProvider) => action.payload),
switchMap((provider) => {
let result: any;
let provi = provider;
if (provider === 'google') {
result = this.firebaseAuthService.signInGoogleLogin();
} else if (provider === 'facebook') {
result = this.firebaseAuthService.signInFacebookLogin();
} else if (provider === 'twitter') {
result = this.firebaseAuthService.signInTwitterLogin();
}
const resultAction: Observable<Action> = result.pipe(
switchMap((userSignIn) => {
console.log("TCL: AuthEffects -> userSignIn", userSignIn)
return combineLatest(this.afAuth.authState.pipe(take(1)), of(userSignIn));
}),
switchMap(([user, userFromProvider]) => {
console.log("TCL: AuthEffects -> user", user)
const userEmail = user.email ? user.email : userFromProvider.additionalUserInfo.profile.email;
const userDto: CreateUserProviderDto = {
uid: user.uid,
fullName: user.displayName,
username: userEmail,
email: userEmail,
terms: true
};
return combineLatest(of(user), from(user.getIdToken()), this.usersService.usersSignInProviderPost(userDto));
}),
map(([user, token, userFromBackend]) => {
const currentUser: CurrentUser = {
token: token, refreshToken: user.refreshToken, user: {
_id: userFromBackend._id,
uid: userFromBackend.uid,
email: userFromBackend.email,
profile: userFromBackend.profile,
fullName: userFromBackend.fullName,
username: userFromBackend.username
}
};
this.localStorageService
.setItem(AUTH_KEY, {
token: token,
refreshToken: user.refreshToken,
isAuthenticated: true,
user: currentUser.user
});
this.ngZone.run(() => {
this.router.navigate(['/']);
});
return new SigninProviderSuccess(currentUser);
}),
catchError(async (error) => {
let displayMessage;
if (error.email && error.credential && error.code === 'auth/account-exists-with-different-credential') {
const providers = await this.afAuth.auth.fetchSignInMethodsForEmail(error.email)
const firstPopupProviderMethod =
providers.find(p => this.firebaseAuthService.supportedPopupSignInMethods.includes(p));
// Test: Could this happen with email link then trying social provider?
if (!firstPopupProviderMethod) {
throw new Error(`Your account is linked to a provider that isn't supported.`);
}
const linkedProvider = this.firebaseAuthService.getProvider(firstPopupProviderMethod);
linkedProvider.setCustomParameters({ login_hint: error.email });
const resultProvider = await this.afAuth.auth.signInWithPopup(linkedProvider);
await resultProvider.user.linkWithCredential(error.credential);
return new SigninProvider(provi);
} else if (typeof error === 'object'
&& error !== null
&& error.hasOwnProperty('code')
&& error.hasOwnProperty('message')) {
const errorNoTypes: any = { ...error };
displayMessage = `${errorNoTypes.code} - ${error.message}`;
this.toastrService.danger('Try it again!', displayMessage, {
duration: 8000
});
}
return new RetrieveError(error);
}),
);
return resultAction;
})
);