Angular/Firebase - Guard 在 Firebase 初始化完成之前运行
Angular/Firebase - Guard runs before Firebase initialization is done
在此处查看问题(打开控制台):
https://stackblitz.com/edit/angular-su5p89?file=src%2Fapp%2Fapp.module.ts
我在 AppModule
中导入并调用了 initalizeApp
,如下所示:
import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestoreModule } from '@angular/fire/firestore';
@NgModule({
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
// Firebase
AngularFireModule.initializeApp(environment.firebase),
AngularFirestoreModule,
AngularFireAuthModule,
// App
AppRoutingModule
],
declarations: [
AppComponent
],
bootstrap: [AppComponent]
})
export class AppModule {}
然后我创建了一个如下所示的守卫:
import { Injectable } from '@angular/core';
import { CanActivate, CanActivateChild, CanLoad } from '@angular/router';
import * as firebase from 'firebase/app';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate, CanActivateChild, CanLoad {
/** @ignore */
constructor() {}
canLoad(): boolean {
return this.performCheck();
}
canActivate(): boolean {
return this.performCheck();
}
canActivateChild(): boolean {
return this.performCheck();
}
private performCheck() {
return !!firebase.auth().currentUser;
}
}
并像这样使用它:
export const Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: 'hello'
},
{
path: 'hello',
component: HelloComponent,
canActivate: [AuthGuard]
}
];
但是,这会产生以下错误:
ERROR Error: Uncaught (in promise): [DEFAULT]: Firebase: No Firebase
App '[DEFAULT]' has been created - call Firebase App.initializeApp()
(app/no-app). [DEFAULT]: Firebase: No Firebase App '[DEFAULT]' has
been created - call Firebase App.initializeApp() (app/no-app).
at error (index.cjs.js:361)
at app (index.cjs.js:244)
at Object.serviceNamespace [as auth] (index.cjs.js:302)
at AuthGuard.performCheck (auth.guard.ts:35)
at AuthGuard.canActivate (auth.guard.ts:29)
at eval (check_guards.ts:121)
at Observable.eval [as _subscribe] (defer.ts:59)
at Observable._trySubscribe (Observable.ts:231)
at Observable.subscribe (Observable.ts:212)
at TakeOperator.call (take.ts:72)
at resolvePromise (zone.js:831)
at resolvePromise (zone.js:788)
at eval (zone.js:892)
at ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (ng_zone.ts:262)
at ZoneDelegate.invokeTask (zone.js:422)
at Zone.runTask (zone.js:195)
at drainMicroTaskQueue (zone.js:601)
当查看其他问题时,这意味着该应用程序尚未初始化 Firebase,这很奇怪,因为我在其他任何事情之前都这样做了。理论上,守卫应该 运行 AFTER 所有这些都会发生,对吗?
我该如何解决这个问题?
我会以不同的方式配置守卫,因为出于某种原因这一行:
import * as firebase from 'firebase/app';
导致第二次初始化并且没有调用导致错误的 initializeApp()
方法。
import { Injectable } from '@angular/core';
import { CanActivate, CanActivateChild, CanLoad } from '@angular/router';
import { AngularFireAuth } from '@angular/fire/auth'; // instead of firebase
import { Observable } from 'rxjs';
import { take, map } from 'rxjs/operators'
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate, CanActivateChild, CanLoad {
/** @ignore */
constructor(private auth: AngularFireAuth) {}
canLoad(): Observable<boolean> {
return this.performCheck();
}
canActivate(): Observable<boolean> {
return this.performCheck();
}
canActivateChild(): Observable<boolean> {
return this.performCheck();
}
private performCheck(): Observable<boolean> {
return this.auth.user.pipe(map((user) => {
if (user) {
// user is logged in
return true;
}
// user is not logged in
return false;
}),
take(1));
}
}
在此处查看问题(打开控制台):
https://stackblitz.com/edit/angular-su5p89?file=src%2Fapp%2Fapp.module.ts
我在 AppModule
中导入并调用了 initalizeApp
,如下所示:
import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestoreModule } from '@angular/fire/firestore';
@NgModule({
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
// Firebase
AngularFireModule.initializeApp(environment.firebase),
AngularFirestoreModule,
AngularFireAuthModule,
// App
AppRoutingModule
],
declarations: [
AppComponent
],
bootstrap: [AppComponent]
})
export class AppModule {}
然后我创建了一个如下所示的守卫:
import { Injectable } from '@angular/core';
import { CanActivate, CanActivateChild, CanLoad } from '@angular/router';
import * as firebase from 'firebase/app';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate, CanActivateChild, CanLoad {
/** @ignore */
constructor() {}
canLoad(): boolean {
return this.performCheck();
}
canActivate(): boolean {
return this.performCheck();
}
canActivateChild(): boolean {
return this.performCheck();
}
private performCheck() {
return !!firebase.auth().currentUser;
}
}
并像这样使用它:
export const Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: 'hello'
},
{
path: 'hello',
component: HelloComponent,
canActivate: [AuthGuard]
}
];
但是,这会产生以下错误:
ERROR Error: Uncaught (in promise): [DEFAULT]: Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app). [DEFAULT]: Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app). at error (index.cjs.js:361) at app (index.cjs.js:244) at Object.serviceNamespace [as auth] (index.cjs.js:302) at AuthGuard.performCheck (auth.guard.ts:35) at AuthGuard.canActivate (auth.guard.ts:29) at eval (check_guards.ts:121) at Observable.eval [as _subscribe] (defer.ts:59) at Observable._trySubscribe (Observable.ts:231) at Observable.subscribe (Observable.ts:212) at TakeOperator.call (take.ts:72) at resolvePromise (zone.js:831) at resolvePromise (zone.js:788) at eval (zone.js:892) at ZoneDelegate.invokeTask (zone.js:423) at Object.onInvokeTask (ng_zone.ts:262) at ZoneDelegate.invokeTask (zone.js:422) at Zone.runTask (zone.js:195) at drainMicroTaskQueue (zone.js:601)
当查看其他问题时,这意味着该应用程序尚未初始化 Firebase,这很奇怪,因为我在其他任何事情之前都这样做了。理论上,守卫应该 运行 AFTER 所有这些都会发生,对吗?
我该如何解决这个问题?
我会以不同的方式配置守卫,因为出于某种原因这一行:
import * as firebase from 'firebase/app';
导致第二次初始化并且没有调用导致错误的 initializeApp()
方法。
import { Injectable } from '@angular/core';
import { CanActivate, CanActivateChild, CanLoad } from '@angular/router';
import { AngularFireAuth } from '@angular/fire/auth'; // instead of firebase
import { Observable } from 'rxjs';
import { take, map } from 'rxjs/operators'
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate, CanActivateChild, CanLoad {
/** @ignore */
constructor(private auth: AngularFireAuth) {}
canLoad(): Observable<boolean> {
return this.performCheck();
}
canActivate(): Observable<boolean> {
return this.performCheck();
}
canActivateChild(): Observable<boolean> {
return this.performCheck();
}
private performCheck(): Observable<boolean> {
return this.auth.user.pipe(map((user) => {
if (user) {
// user is logged in
return true;
}
// user is not logged in
return false;
}),
take(1));
}
}