Angular AuthGuard 和登录持久性:即使已登录,路由器也会自动重定向到 non-truthy 路由

Angular AuthGuard and login persistence: Router automatically redirects to non-truthy route even if logged in

如标题所示,我想通过 canLoad 保护路由。这在某种程度上起作用。但是,我的代码有两个问题。

这是我的代码片段

AppComponent

ngOnInit(): void {
    this.authServ.reauthenticate().subscribe()
}

AuthService

user = new BehaviorSubject<User>(null as any);
reauthenticate(): Observable<User> {
    // return HTTP call here and pipe the user data into user BehaviorSubject
}

AuthGuard

canLoad(){
      return this.authServ.user.pipe(
        map((user) => {
          if (!!user?._token) {
            return true;
          }
          this.router.navigate(['/login']);
          return false;
        })
      );
}

如您所料,路由器可以访问用户,但仍会重定向到 /login 路径。知道它不起作用,我 brute-forced 按我的方式对服务器进行两次 HTTP 调用(我知道这通常很糟糕)以诱使系统确认持久用户。这是代码片段。

AuthGuard

canLoad() {
      return this.authServ.user.pipe(
        switchMap((user) => {
          if (!!user && !!user._token) {
            return of(user);
          }
          return this.authServ.reauthenticate();
        }),
        map((user) => {
          if (!!user?._token) {
            return true;
          }
          this.router.navigate(['/login']);
          return false;
        })
      );
}

所以我的问题归结为以下两件事之一:

  1. 如何确保我只调用 re-tokenizer 端点一次但仍然不会继续在刷新时不被路由?
  2. 如何才能使 BehaviorSubject 正常工作,直到我收到用户 object?

我检查了以下链接: 。但是,在使用 Subject 后,我可能需要在每次访问违反直觉的受保护路由时重新验证用户。

好的,我已经解决了这个问题。我所做的是在 AuthService 中创建一个新的 Subject。守卫检查 AuthService returns 中的 BehaviorSubject 是否为 null,如果是,我将 switchMap 使用 Subject。这是代码。

AuthGuard

canLoad() {
    return this.authServ.user.pipe(
        switchMap((user) => {
          if (!!user && !!user._token) {
            return of(user);
          }
          return this.authServ.initialLogin;
        }),
        map((user) => {
          if (!!user?._token) {
            return true;
          }
          this.router.navigate(['/login']);
          return false;
        })
}

AuthService

user = new BehaviorSubject<User>(null as any);
initialLogin = new Subject<User>();
reauthenticate(): Observable<User> {
    // return HTTP call here and pipe the user data into user BehaviorSubject
    return this.http.get<User>(URL, {withCredentials: true}).pipe(tap((user) => {
        this.initialLogin.next(user);
        this.user.next(user);
    }))
}

AppComponent

ngOnInit(): void {
    this.authServ.reauthenticate().subscribe()
}

这样,我只在项目开始时验证一次