Guard canActivate 在服务实例化之前运行

Guard canActivate runs before service is instantiated

这很可能是一个非常微不足道的问题,我只是从 AngularJS 背景中挑选 Angular 2+。

最简单的是,我在我的 angular 9 应用程序中实施身份验证,但我的警卫遇到了一个问题。

在我的 authentication.service.ts 服务中,我使用的是用户类型的 BehaviourSubject,并且我使用以下公共库将我的用户对象保存在 localStorage 中:https://github.com/cyrilletuzi/angular-async-local-storage

在我的 authentication.service 构造函数中,我正在做这样的事情:

constructor(private request: RequestService, private storage: StorageMap) {
    this.storage.get('currentUser').subscribe((user: User) => {
      this.currentUserSubject = new BehaviorSubject<User>(user);
      this.currentUser = this.currentUserSubject.asObservable();
    });
  } 

和我的 isAuthenticated 方法:

isAuthenticated() {
    return this.currentUserSubject.value;
  }

这很好用,但是,因为 storageMap 是一个可观察对象,它需要很少的时间才能 return,因此当我尝试检查用户是否在我的守卫中经过身份验证时:

canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return this.authService.isAuthenticated();
  } 

很遗憾,this.currentUserSubject 未定义。所以守卫 运行 在 authentication.service 中的构造函数有机会正确实例化之前。

如有任何积分,将不胜感激。

更新:

我想我越来越接近了。

在我的 authentication.service 中,我的 isAuthenticated 方法现在看起来像这样(如下所示)

isAuthenticated() {
return this.currentUser
  .pipe(filter(user => user));

}

虽然有错误:参数类型用户不可分配给参数类型。

此外,如果我在 canActivate 中更改我的 return 语句:

canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.authService.isAuthenticated();

}

但我在控制台中得到了这个

类型 'Observable' 不能分配给类型 'Observable'。 类型 'unknown' 不能分配给类型 'boolean | UrlTree'。 类型“{}”缺少类型 'UrlTree' 中的以下属性:root、queryParams、fragment、queryParamMap

18     return this.authService.isAuthenticated();

canActivate方法必须returnObservable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree.

据我所知,您正在 return 对象(用户)。

但是,在你的守卫中,你应该使用可观察的而不是主题。

canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> {
    return this.authService.currentUser.pipe(map(user => !!user));
  } 

map 运算符的双重否定 (!!) 将使 return 的可观察值成为布尔值。

Guards 在导航时被激活,所以在导航到 post 登录页面之前,请确保您已设置用户。

constructor(private authenticationService: AuthenticationService, private router: Router) {}

ngOnInit() {
    this.handleUserChange();
}

private handleUserChange(): void {
    this.authenticationService.currentUserSubject
    .pipe(filter(user => user)) // falsy value check
    .subscribe(user => 
    {
         // Navigate to post login
         this.router.navigate(['home-page']);
    }
}
async isAuthenticated() {
    var res = await this.storage.get('currentUser').toPromise();
    return res;
}

您遇到的行为的原因是,订阅是一项异步作业。所以 class 一调用订阅就完成了初始化。订阅的回调将在稍后拥有该数据时调用。在调用您的回调之前,您已被调用。