AngularFireAuth 模拟器登录在页面重新加载时丢失

cod*_*lex 9 firebase angularfire firebase-authentication angularfire2

我的 Angular 项目成功地使用AngularFireAuth来自@angular/fire的注入连接到本地 Firebase 身份验证模拟器。我使用这些来源作为我的实现参考:

但是,一旦我重新加载页面,登录状态就会丢失,我必须再次登录。

首先,我尝试在 Angular 组件构造函数中像这样设置持久性:

constructor( private _fireauth: AngularFireAuth) {
    this._fireAuth.useEmulator(`http://${location.hostname}:9099/`);
    this._fireauth.setPersistence(firebase.auth.Auth.Persistence.LOCAL);
}
Run Code Online (Sandbox Code Playgroud)

这没有什么区别。然后我在浏览器网络控制台中注意到,firebase 库在页面加载后确实找到了本地存储的会话,但最初尝试联系谷歌服务器进行验证,这当然失败了,因为它是本地模拟器会话:

在此处输入图片说明

这似乎是有道理的,因为_fireAuth.useEmulator()仅在组件构造函数中调用。应用程序的其他部分,例如AngularFireAuthGuard可能会尝试更早地访问身份验证状态方式。useEmulator()在应用程序的任何其他部分可能尝试访问身份验证状态失败之前,尝试调用几次:

  • Attempt1:调用useEmulator()@Injectable({providedIn: 'root'})又名服务构造
  • Attempt2:提供一个APP_INITIALIZER在应用程序被引导之前执行代码的方法:
export function initializeApp1(afa: AngularFireAuth): any {
  return () => {
    return new Promise(resolve => {
      afa.useEmulator(`http://${location.hostname}:9099/`);
      setTimeout(() => resolve(), 5000);
    });
  };
}

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...,
    AngularFireModule.initializeApp(environment.firebase),
    AngularFireAuthModule,
    ...
  ],
  providers: [
     AngularFireAuth,
     {
       provide: APP_INITIALIZER,
       useFactory: initializeApp1,
       deps: [AngularFireAuth],
       multi: true
     }
  ],
  bootstrap: [AppComponent]
})

Run Code Online (Sandbox Code Playgroud)
  • Attempt3:提供似乎在构造函数中实现USE_EMULATORInjectable :AngularFireAuth
  providers: [
     {
       provide: USE_EMULATOR,
       useValue: [location.hostname, 9099]
     },
  ]
Run Code Online (Sandbox Code Playgroud)

我想特别是Attempt3会尽可能早地设置模拟器模式,因为它可以比在构造函数中设置早多少?注射似乎工作,因为浏览器控制台打印在页面加载通常的警告消息:auth.esm.js:133 WARNING: You are using the Auth Emulator, which is intended for local testing only. Do not use with production credentials.。但是,googleapis.com每次在页面加载时检测到本地 indexedDB 中存储的会话时,仍然会触发对 的请求,然后我注销了。还值得注意的是:在Attempt2我使用 5 秒超时显着减慢应用程序初始化速度googleapis.com后,在 Angular 完成初始化之前,页面加载后立即触发请求。

在这一点上,我不知道该尝试什么了。@angular/fire 显然是建立在基本的 Firebase JavaScript 库上的,所以我可能需要更早地设置模拟器模式,但也许我在这里走错了方向?

================================================== ==============

[编辑:]似乎结合Attempt 2Attempt 3作品,只要该initializeApp1()方法使用一个setTimout()的至少约 100 毫秒。当我删除超时或将其设置为低至 10 毫秒时,登录就会丢失。任何超过 100 毫秒的超时也有效。在这一点上它看起来非常像一个竞争条件?

工作示例:

  providers: [
     {
       provide: USE_EMULATOR,
       useValue: [location.hostname, 9099]
     },
  ]
Run Code Online (Sandbox Code Playgroud)

我也注意到这条评论AngularFireAuth源代码。到目前为止,我真的不明白发生了什么,但也许问题是相关的:

// HACK,当我们导出 auth.Auth 而不是 auth 时,导入 firebase.auth(例如,import { auth } from 'firebase/app')的开发人员意外地获得了未定义的 auth 对象,因为我们完全懒惰。让我们在这里急切地加载 Auth SDK。仍然可能存在竞争条件……但这大大降低了我们重新评估 API 的可能性。

小智 0

我在代码中调整了初始化应用程序函数,以使用 rxjs 而不是 Promise。

export const initializeApp = (angularFireAuth: AngularFireAuth): (() => Observable<boolean>) => {
    if (!environment.firebaseConfig.useEmulator) {
        return () => of(true);
    } else {
        return () => of(true).pipe(
            delay(100),
            tap(_ => {
                angularFireAuth.useEmulator('http://localhost:9099/');
            })
        );
    }
};
Run Code Online (Sandbox Code Playgroud)