javascript - AngularFirebaseAuth : Calling server api just after firebase auth?

标签 javascript angular typescript firebase rxjs

我的身份验证基于两件事:

  • firebase 身份验证(电子邮件/密码)
  • 调用服务器 API 以从 BDD 和 firebaseID 检索完整的客户实体(用户必须存在) 因此,如果满足这两个条件,用户将被“认证”。

我还有一个基于返回 Observable 的 isAuthenticated() 的 authGuard(因为在页面刷新时,守卫必须等待身份验证完成,然后才能将用户重定向到任何地方)。

问题:我找不到一种方法让它与所有异步和 rxjs 困惑/ hell 一起工作。目前它正在工作,但每次调用 isAuthenticated 时,都会调用 serverAPI auth时间... 我怎样才能重构它以便只调用服务器一次并且所有异步/重新加载的东西仍然有效?

授权服务:

export class AuthService {
    public userRole: UserBoRole;
    public authState$: Observable<firebase.User>;

    constructor(
        private afAuth: AngularFireAuth,
        private snackBar: SnackBarService,
        private translate: TranslateService,
        private router: Router,
        private grpcService: GrpcService
    ) {
        this.authState$ = this.afAuth.authState.pipe(
            take(1),
            mergeMap(user => {
                if (!user) {
                    return of(user);
                }

                // User is successfully logged in,
                // now we need to check if he has a correct role to access our app
                // if an error occured, consider our user has not logged in, so we return null
                return this.checkProfile().pipe(
                    take(1),
                    map(() => {
                        this.test = true;
                        return user;
                    }),
                    catchError(err => {
                        console.error(err);
                        return of(null);
                    })
                );
            })
        );

        // Subscribing to auth state change. (useless here because access logic is handled by the AuthGuard)
        this.authState$.subscribe(user => {
            console.log('authState$ changed :', user ? user.toJSON() : 'not logged in');
        });
    }

    checkProfile() {
        return this.callAuthApi().pipe(
            map((customer) => {
                if (!customer || customer.hasRole() === "anonymous") {
                    return Promise.reject(new Error(AuthService.AUTH_ERROR_ROLE));
                }
                this.userRole = customer.getRole();
            })
        );
    }

    isAuthenticated(): Observable<boolean> {
        return this.authState$.pipe(map(authState => !!authState));
    }
}

授权 guard :

export class AuthGuard implements CanActivate, CanActivateChild {
    constructor(private authService: AuthService, private router: Router) {}

    check(): Observable<boolean> {
        return this.authService.isAuthenticated().pipe(
            catchError(err => {
                // notifying UI of the error
                this.authService.handleAuthError(err);

                // signout user
                this.authService.signOut();

                // if an error occured, consider our user has not logged in
                return of(false);
            }),
            tap(isAuthenticated => {
                if (!isAuthenticated) {    
                    // redirecting to login
                    this.router.navigate(['login']);
                }
            })
        );
    }

    canActivateChild(): Observable<boolean> {
        return this.check();
    }

    canActivate(): Observable<boolean> {
        return this.check();
    }
}

谢谢

最佳答案

您可以更改您的 checkProfile() 函数以在出现错误时返回 observable 而不是来自 http 请求或 promise 的 observable。首先,您将检查用户是否已经通过身份验证(我假设 userRole 会很好,因为您在调用后端后保存它)如果是,则返回一个新创建的可观察对象而不调用您的后端,否则您将发出请求并发出您可观察到基于 http 调用的结果。在下一个示例中,您将只调用一次:

checkProfile() {
  return new Observable((observer) => {
    if (this.userRole) {
      observer.next();
      observer.complete();
    } else {
      this.callAuthApi().pipe(
          map((customer) => {
            if (!customer || customer.hasRole() === "anonymous") {
              observer.error(new Error(AuthService.AUTH_ERROR_ROLE));
              observer.complete();
            }
            this.userRole = customer.getRole();
            observer.next();
            observer.complete();
          })
      );
    }
  });
}

关于javascript - AngularFirebaseAuth : Calling server api just after firebase auth?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52896245/

相关文章:

javascript - 代码流程误解?

Javascript 数组索引减一

Angular:仅在为产品构建时获取模块未找到错误

javascript - 当一个项目从带 Angular 子对象传递时获取父 ID

angularjs - Visual Studio Code 提示 *.d.ts 文件中定义的类型为 "Cannot find namespace"

javascript - 使用 ngImgCrop 绕过 Typescript

javascript - mootools 获取没有 ID 的元素的位置

javascript - 为什么在生产中使用没有括号的函数是不好的?

javascript - 在 VisJs 中创建网络图时选项对象出错(Angular 4)

javascript - 将 JSON 格式化为特定结构