Angular: Run canActivate on each route change

Fil*_*tys 8 router canactivate angular

I got stuck recently with Angular route guards. CanActive runs only once when the page is loaded and does not run on route change within the guarded route. I think this was changed because it used to run on each change. From what I read in forums, I should use CanActivateChild. The thing is, our application consists of several modules, that have several route descendants and when I use CanActivateChild in root module, it is called several times when changing the route.

I find it dumb to assign a guard to each child because, for AppModule, those lazy loaded child modules should be just 'Black Boxes' and I wanted to define that all those modules should be guarded.

export const routes: Routes = [
  {
    path: '404',
    component: NotFoundComponent
  },
  {
    path: '',
    canActivate: [AuthGuard],
    component: FullLayoutComponent,
    data: {
      title: 'Home'
    },
    children: [
      {
        path: 'administration',
        loadChildren: './administration/administration.module#AdministrationModule'
      },
      {
        path: 'settings',
        loadChildren: './settings/settings.module#SettingsModule'
      }
    ]
  },
  {
    path: '',
    loadChildren: './account/account.module#AccountModule'
  },
  {
    path: '**',
    redirectTo: '404'
  }
];
Run Code Online (Sandbox Code Playgroud)

Is there any solution to this? Or do You find this as 'not an issue' regarding security?

Thank You all.

lir*_*006 6

面对同样的问题,我只能在Github上用Angular devs声明这些行为“是设计使然”的封闭问题上找到的。

因此,我最终要做的是订阅app.component中的导航事件并触发AuthGuard检查:

constructor(
  private router: Router,
  private route: ActivatedRoute,
  private authGuard: AuthGuard,
) {}

ngOnInit() {
  this.router.events
    .subscribe(event => {
      if (event instanceof RoutesRecognized) {
        this.guardRoute(event);
      }
    }));
}

private guardRoute(event: RoutesRecognized): void {
  if (this.isPublic(event)) {
    return;
  }

  if (!this.callCanActivate(event, this.authGuard)) {
    return;
  }
}

private callCanActivate(event: RoutesRecognized, guard: CanActivate) {
  return guard.canActivate(this.route.snapshot, event.state);
}

private isPublic(event: RoutesRecognized) {
  return event.state.root.firstChild.data.isPublic;
}
Run Code Online (Sandbox Code Playgroud)

AuthGuard是相当标准的:

@Injectable()
export class AuthGuard implements CanActivate{

  constructor(private auth: AuthService, private router: Router) { }

  canActivate(): Promise<boolean> {
    return this.auth.isLoggedInPromise()
      .then(isLoggedIn => {
        if (!isLoggedIn) {
          this.router.navigate(["/login"]);
        }
        return isLoggedIn;
      });
    }
  }
Run Code Online (Sandbox Code Playgroud)

并且公共路由应配置如下:

{
  path: "login",
  component: LoginComponent,
  data: { isPublic: true }
}
Run Code Online (Sandbox Code Playgroud)

这种实现的好处是,默认情况下所有内容都受保护,并且应该显式配置公用路由,这将减少使某些路由不受保护的可能性。还将其重构为某种服务,以便能够在多个应用程序中使用它。

受到这个答案的启发。