Angular 基于两个可观察值的守卫

Angular guard based on two observables

我正在尝试做一个“AdminGuard”,它应该基于两件事:

  1. 用户是否登录?
  2. 用户是否有管理员权限?

我有一个 AuthService,它提供两个 Observable

我做了以下事情:

@Injectable({
  providedIn: 'root'
})
export class IsAdminGuard implements CanActivate {
  constructor(private auth: AuthService, private router: Router) { }


  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> {
      console.log(this.auth)

      return combineLatest([this.auth.isLoggedIn, this.auth.isAdmin]).pipe(
        take(1),
        map((authInfo) => {
          console.log(authInfo)
          if (!authInfo[0]) {
            console.error('Access denied - Unauthorized')
            return this.router.parseUrl('/auth/');
          } else if (!authInfo[1]) {
            console.error('Access denied - Admin only')
            return this.router.parseUrl('/auth/unauthorized');
          } else {
            return true;
          }
        })
      );
  }

}

console.log(this.auth) 被调用并且似乎具有有效值,但第二个 console.log 从未被调用并且我的组件未加载。

如果我从我的路线中移除守卫:

  {
    path: 'admin',
    component: AdminComponent,
    //canActivate: [IsAdminGuard],
  }

它有效,所以我很确定是 IsAdminGuard 不起作用。

我还显示了一些基于相同布尔值的其他东西(一些 *ngIf="authService.IsLoggedIn | async" 正在工作,所以我真的不明白我搞砸了什么?

编辑 以下是我如何在我的 AuthService 中更新 IsLoggedIn/IsAdmin/IsUser 的不同值:

 constructor(public afAuth: AngularFireAuth, public router: Router, private afStore: AngularFirestore) {
    this.afAuth.authState.subscribe(async user => {
      console.log('handling auth')
      if (this._roleSubscription) {
        this._roleSubscription.unsubscribe();
        this._roleSubscription = undefined;
      }
      if (user) {
        this._user.next(user);
        this._isLoggedIn.next(true);
        this._roleSubscription = this.afStore.doc<Roles>(`roles/${user.uid}`).valueChanges().subscribe(role => {
          console.log('updating roles', role)
          if (role) {
            this._isAdmin.next(role.admin == true)
            this._isUser.next(role.admin == true || role.user == true);//Admin have also an heart, they are users too!
          } else {
            this._isAdmin.next(false);
            this._isUser.next(false);
          }
        });
      } else {
        this._user.next(undefined);
        this._isLoggedIn.next(false);
        this._isAdmin.next(false);
        this._isUser.next(false);
        await this.router.navigate(['/auth']);
      }
      console.log('values updated')
    })
  }

您必须使用发出最新值的 ReplaySubject。主题仅在有活动订阅时才会发出,而 BehaviorSubject 总是在以初始值

开始时发出
readonly _isLoggedIn = new ReplaySubject<boolean>(1);
readonly _isAdmin = new ReplaySubject<boolean>(1);