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

{
    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;
   }

}

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

最佳答案

需要了解的非常重要的一点是,在 AuthGuard 中,您进行了 异步 调用,但我们不知道它何时会被解决。其他代码是 同步 并且将立即执行而无需等待此异步调用(这就是 userundefined 的原因)。

但是您可以强制 AdminGuard 等待,而您的 HTTP 调用将得到解决:为此,您可以存储 Observable Subscription (因为您正在使用 observable ,但您也可以使用 promise 执行相同的技巧)到 AuthServiceAuthGuard(您进行 HTTP 调用的地方)使用以下行:

this.authService.subscription$ = this.http.get('https://jsonplaceholder.typicode.com/users');

现在您的订阅位于 AuthService 中,您所需要的只是在两个守卫中对其进行 subscribe (在您的情况下使用 .map() ):

AuthGuard:
return this.authService.subscription$.map(res => {
  this.authService.user = {role: 'admin'};
  return true;
});

AdminGuard:
return this.authService.subscription$.map(res => {
  if (this.authService.user.role === 'admin') {
    return true;
  }
});

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

如果您在控制台中看到 "AuthGuard returns TRUE!""AdminGuard returns TRUE!" - 一切正常。我还从 this.authService.userAuthGuard 记录了 AdminGuard 变量。

关于javascript - Angular 5(Angular 2+),第二个守卫不等待第一个守卫完成http请求,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48241851/

10-11 07:24