Angular 5(Angular 2+),第二个守卫不等待第一个守卫完成http请求

Igo*_*gor 6 javascript request typescript angular

我有一个应用程序,其中有两个警卫(AuthGuard - 用于登录用户,AdminGuard - 用于管理员)。首次加载时 AuthGuard 会发出 http 请求以从 API 获取用户信息。问题是,当您尝试使用两个防护访问路由时,AdminGuard 不会等待 AuthGuard 完成请求并设置用户,以便 AdminGuard 可以检查用户的角色,并且应用程序会中断。我知道它会崩溃,因为用户未定义。我正在寻找如何让第二个守卫等待第一个守卫完成的解决方案。

{
    path: 'admin',
    component: AdminComponent,
    canActivate: [AuthGuard, AdminGuard]
},

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(
    private authService: AuthService,
    private http: HttpClient) { }

    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

        return this.http.get('https://jsonplaceholder.typicode.com/users').map(res => {
            console.log('Auth Guard.');
            console.log(res);
            this.authService.user = {role: 'admin'};

            return true;
     });

         return false;
    }
}

@Injectable()
export class AdminGuard implements CanActivate {
    constructor(private authService: AuthService) { }

    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

        console.log('Admin Guard.');
        console.log(this.authService.user);

        if (this.authService.user.role === 'admin') {
             return true;
        }

        return false;
   }
Run Code Online (Sandbox Code Playgroud)

}

这是一个 plnker 链接 - http://plnkr.co/edit/EqgruNjogTJvsC1Zt5EN?p=preview

Com*_*ide 4

需要理解的非常重要的一点是,当AuthGuard您进行异步调用时,我们不知道它何时会得到解决。其他代码是同步的,将立即执行,而无需等待此异步调用(这就是useris的原因undefined)。

但是你可以强制AdminGuard等待,而你的 HTTP 调用将被解析:为此,你可以将Observable 订阅(因为你正在使用observable,但你也可以做同样的技巧promise)存储到AuthServicefrom AuthGuard(你在其中创建 HTTP调用)使用以下行:

this.authService.subscription$ = this.http.get('https://jsonplaceholder.typicode.com/users');
Run Code Online (Sandbox Code Playgroud)

现在您的订阅位于 中AuthService,您所需要做的就是subscribe在两个防护中进行订阅(您.map()在您的情况下使用):

授权卫士:

return this.authService.subscription$.map(res => {
  this.authService.user = {role: 'admin'};
  return true;
});
Run Code Online (Sandbox Code Playgroud)

管理员卫士:

return this.authService.subscription$.map(res => {
  if (this.authService.user.role === 'admin') {
    return true;
  }
});
Run Code Online (Sandbox Code Playgroud)

这是工作插件: http://plnkr.co/edit/R2Z26GsSvzEpPdU7tOHO ?p=preview

如果您在控制台中看到"AuthGuard returns TRUE!"和- 一切都应该正常工作。"AdminGuard returns TRUE!"我还记录了来自和this.authService.user的变量。AuthGuardAdminGuard