Angular: Run canActivate on each route change

笑着哭i 提交于 2021-02-18 06:09:06

问题


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'
  }
];

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

Thank You all.


回答1:


Faced the same issue and all I was able to find on issue are few closed issues on Github with Angular devs statements that such behavior "is by design".

So what I ended up doing is subscribing on navigation events in app.component and firing AuthGuard check there:

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

AuthGuard is rather standard:

@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;
      });
    }
  }

And public routes should be configured like this:

{
  path: "login",
  component: LoginComponent,
  data: { isPublic: true }
}

The plus of such implementation is that everything is protected by default and public route should be configured explicitly, which will reduce the possibility of leaving some routes unprotected. Will also refactor this into some kind of service, to be able to use it across multiple apps.

Inspired by this answer.




回答2:


The issue with subscribing to router events is that the navigation has already been started and the history has been updated, which makes it hard to prevent the navigation in a reliable way as a guard does.

But Angular has learned to provide you with a way to configure how guards and resolvers should behave directly in your routes.ts:

export const routes: Routes = [
  {
    path: '404',
    component: NotFoundComponent
  },
  {
    path: '',
    canActivate: [AuthGuard],
    runGuardsAndResolvers: 'always',
    children: [
       ....
    ]
  }
]

Here's the docs: https://angular.io/api/router/RunGuardsAndResolvers

There's a nice blogpost explaining your options: https://juristr.com/blog/2019/01/Explore-Angular-Routers-runGuardsAndResolvers/



来源:https://stackoverflow.com/questions/46805117/angular-run-canactivate-on-each-route-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!