我正在使用Firbase在我的Ionic 3应用中实施Google登录。我已成功使用native Google Plus Cordova plugin,然后使用Angular Fire 2使用凭据登录Firebase。这是我的代码:
public loginWithGoogle(): Promise<any> {
return new Promise((resolve, reject) => {
let loginPromise: Promise<any>;
if (this.isMobile()) {
loginPromise = new Promise((resolve, reject) => {
this.googleplus.login({
'webClientId': '--------.apps.googleusercontent.com',
'offline': true
})
.then(res => {
this.afAUth.auth.signInWithCredential(firebase.auth.GoogleAuthProvider.credential(res.idToken))
.then(firebaseRes => {
resolve(firebaseRes);
})
.catch(err => {
reject(err);
});
})
.catch(err => {
reject(err);
});
});
} else {
loginPromise = this.afAUth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()) as Promise<any>;
}
loginPromise
.then(res => {
console.log('login promise done: ' + JSON.stringify(res));
const user: User = {
uid: res.user.uid,
email: res.user.email,
displayName: res.user.displayName
};
resolve(user);
});
});
}
在我的登录页面中调用它:
this.auth.loginWithGoogle()
.then(res => {
console.log('success login !!!!!');
})
.catch(err => {
console.log('error login !!!!!');
});
但是,当我使用Xcode部署到iOS时,我可以看到控制台输出:
2017-06-11 11:32:01.384130 MyApp[2634:842028] login promise done: {"uid":"...","displayName":"...","photoURL":"..."...}
承诺永远不会解决!我已尝试手动使用ZoneJS但未成功:
private zone;
public loginWithGoogle(): Promise<any> {
this.zone = new NgZone({});
...
this.zone.run(() => {
resolve(user);
});
});
});
}
但结果是一样的。有关信息,登录在浏览器中正常工作。
答案 0 :(得分:1)
问题来自访问res.user
,仅在使用弹出窗口登录时才存在。使用凭据登录时返回的对象在其根目录中包含uid
,email
和其他用户属性。无论您是在移动环境还是降压环境中,都需要以不同方式创建用户。在移动设备上,访问res.user.uid
和浏览器访问res.uid
。
恕我直言,这是Angular Fire方面的误导性接口规范。
此外,代码很难阅读。承诺链不是一个好习惯。如果可能,直接使用Observables,如果不可能,使用RxJS fromPromise运算符将promises转换为Observables。然后,您可以将flatMap结果链接到异步调用并获得干净的代码。 Observables的一个优点是subscribe
函数的错误回调将捕获链中发生的任何错误,而使用promises则需要手动捕获和拒绝。
通过一些重构,您可以获得以下(有效):
private signInWithGooglePlus(): Observable<any> {
return Observable.fromPromise(
...
);
}
private signInFirebaseWithCredentials(idToken: string): Observable<User> {
return Observable.fromPromise(
...
).map(credentials => ({
uid: credentials.uid,
...
}));
}
private signInWithGooglePopup(): Observable<User> {
return Observable.fromPromise(
...
).map(firebaseRes => ({
uid: firebaseRes.user.uid,
...
}));
}
public loginWithGoogle(): Observable<any> {
let loginPromise: Observable<User>;
if (this.isMobile()) {
loginPromise = this.signInWithGooglePlus().flatMap(res => this.signInFirebaseWithCredentials(res.idToken));
} else {
loginPromise = this.signInWithGooglePopup();
}
let user: User;
return loginPromise
.flatMap(userTmp => {
user = userTmp;
return this.getJWTToken(userTmp.uid);
})
.map(token => {
this.storeData(token, user);
return user;
});
}