如何让 angular 路由守卫或它调用的服务在评估布尔值之前等待响应?

How can I get an angular route guard, or the service it calls, to wait for a response before evaluating the boolean?

我正在尝试在路由守卫中实现一些基本逻辑,以验证用户是否有权访问 URL。

当用户点击列表中的 link 时,我会获取 firestore 文档 ID 并将该 ID 作为 URL 参数传递到下一页。使用此方法,URL 会显示文档 ID,因此用户可以将 ID 更改为他们无权访问的内容。

我写的路由守卫工作...主要是。不幸的是,路由守卫第一次失败并把你踢回主页,但如果你重新登录,它就会起作用。设置一些断点和调试后,我可以看出评估 ID 和 returns 布尔值的代码没有等待文档用户 ID 的数据库调用。

我假设我需要实现某种 observable,但我不确定我应该在流程的哪个点发出 observable,以及我应该在哪里订阅(服务,还是守卫?)。我开始假设我应该在服务中进行一些调用,但也许将它们放在守卫本身会更好? 感谢您的帮助。

路由守卫

canActivate(route: ActivatedRouteSnapshot): boolean {
    this.pid = route.paramMap.get('pid')
    if (this.authService.isPartyAuth(this.pid) !== true) {
      this.router.navigate(['home'])
    }
    return true;
  }

授权服务

liveUid 正在构造函数中设置,以及 partyCollectionRef

isPartyAuth(pid: string) {

    this.partyCollectionRef.doc(pid).ref.get().then((doc) => {
      if (doc.exists) {
        this.partyUserId = doc.data().uid
      } else {
        console.log("No such document!");
      }
    }).catch(function (error) {
      console.log("Error getting document:", error);
    });
    
    return this.partyUserId == this.liveUid && this.partyUserId !== undefined && this.liveUid !== undefined ? true : false;
  }

你不能return订阅任何东西,改用地图,你还需要添加一个return声明。

canActivate() {
  // add 'return'
  return this.authService.isPartyAuth(this.pid)
   // change this!
   // .subscribe(resp=> {
   .map(resp=> {
     if(!resp) {
        this.router.navigate(['home'])
        return false;
     }
     return true;
   }); 
 }

我进行了一些小调整并使它正常工作:

路由守卫

我将整个函数设为异步,并在对服务的调用中添加了等待。

  async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {

    this.pid = route.paramMap.get('pid')

    if (await this.authService.isPartyAuth(this.pid) !== true) {

      this.router.navigate(['home'])

    }
    
    return true;
  }

}

授权服务

我也更新了auth服务到return我等待后的boolean,得到了文档数据

isPartyAuth(pid: string) {

   return this.partyCollectionRef.doc(pid).ref.get().then((doc) => {
      if (doc.exists) {
        this.partyUserId = doc.data().uid
        return this.partyUserId == this.liveUid && this.partyUserId !== undefined && this.liveUid !== undefined ? true : false;
      } else {
        console.log("No such document!");
        return false
      }
    }).catch(function (error) {
      console.log("Error getting document:", error);
    });


  }