Angular 2+ : canLoad usage

2019-08-21 07:28发布

I'm trying to use the canLoad function with routes, but it doesn't seem to work.

I don't know why, maybe you can't use it with canActivate or something, but since I don't know, I thought someone would here.

The code runs, when serving with aot compilation I get this :

chunk {admin.module} admin.module.chunk.js, admin.module.chunk.js.map () 28 kB {main} {pilotage.module} {suiviprod.module}
chunk {inline} inline.bundle.js, inline.bundle.js.map (inline) 5.83 kB [entry]
chunk {main} main.bundle.js, main.bundle.js.map (main) 3.5 MB {vendor} [initial]
chunk {pilotage.module} pilotage.module.chunk.js, pilotage.module.chunk.js.map () 17.2 kB {admin.module} {main} {suiviprod.module}
chunk {styles} styles.bundle.js, styles.bundle.js.map (styles) 267 kB {inline} [initial]
chunk {suiviprod.module} suiviprod.module.chunk.js, suiviprod.module.chunk.js.map () 20.4 kB {admin.module} {main} {pilotage.module}
chunk {vendor} vendor.bundle.js, vendor.bundle.js.map (vendor) 5.52 MB [initial]

But when I go to the modules, the console log isn't done.

Here is the code of my routes :

logged.module (main routing, see it as app.module)

export const loggedRoutes: Routes = [
  {
    path: 'logged', component: LoggedComponent, canActivate: [AuthGuardService], canActivateChild: [AuthGuardService], children: [
      { path: 'profile', component: ProfileComponent, children: [] },
      ...adminRoutes,
      ...mainRoutes,
      ...pilotageRoutes,
      ...suiviProdRoutes,
      { path: 'admin', loadChildren: 'app/logged/admin/admin.module#AdminModule', canLoad: [AdminGuardService] },
      { path: 'pilotage', loadChildren: 'app/logged/pilotage/pilotage.module#PilotageModule', canLoad: [AdminGuardService] },
      { path: 'suiviprod', loadChildren: 'app/logged/suiviprod/suiviprod.module#SuiviprodModule', canLoad: [AdminGuardService] },
      { path: '', redirectTo: '/logged/main/error', pathMatch: 'prefix' }
    ]
  },
];

admin.module (suiviprod and pilotage are the same, just with different routes & components)

export const adminRoutes: Routes = [
  {
    path: 'admin', component: AdminComponent, canActivate: [AdminGuardService], canActivateChild: [AdminGuardService], children: [
      { path: 'validation', component: ValidationComponent, children: [] },
      { path: 'dashboard', component: DashboardComponent, children: [] },
      { path: 'user/:id', component: UserComponent, children: [] },
      { path: 'users', component: UsersComponent, children: [] },
      { path: 'params', component: ParamsComponent, children: [] },
      { path: 'journals', component: JournalsComponent, children: [] },
      { path: 'purge', component: PurgeComponent, children: [] },
      { path: 'groups', component: GroupsComponent, children: [] },
      { path: 'configs', component: ConfigurationComponent, children: [] },
      { path: 'applications', component: ApplicationsComponent, children: [] },
      { path: '', redirectTo: '/logged/admin/dashboard', pathMatch: 'prefix' }
    ]
  },
];

authguard.service (canActivate returns true if the local storage has a token)

@Injectable()
export class AdminGuardService implements CanActivate, CanActivateChild, CanLoad {
  jwtHelper: JwtHelper = new JwtHelper();
  constructor(private router: Router, private alerter: AlertService) { }
  // tslint:disable-next-line:max-line-length
  canActivate(route?: ActivatedRouteSnapshot, state?: RouterStateSnapshot): boolean { return canActivate(route, state, this, [global.roles.admin]); }
  canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { return this.canActivate(route, state); }
  canLoad(route: Route): boolean { console.log('coucou'); return canActivate(null, null, this, [global.roles.admin]); }
}

EDIT The canActivate function, used by the guard (that works well for canActivate and canActivateChild) :

export function canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot, caller: any, userRoles: string[]): boolean {
  try {
    // Get the token
    let token = localStorage.getItem('jwt');

    // If no token found, not connected
    if (!token) {
      caller.alerter.error(`Vous n'êtes pas connecté`);
      caller.router.navigate(['/login']);
      return false;
    }

    // Try to get roles. If it fails, not a valid token.
    let decodedToken = caller.jwtHelper.decodeToken(token);
    let roles: Array<String> = decodedToken.roles.split(',');

    // return true if any role is found
    let found = false;
    for (let role of userRoles) {
      if (roles.indexOf(role) >= 0) { found = true; }
    }
    if (found) { return true; }

    // Role not found => Unauthorized
    caller.alerter.error(`Autorisation manquante`);
    caller.router.navigate(['/logged/main']);
    return false;

  } catch (ex) {
    // Catch the JWT errors
    caller.alerter.error(`La session utilisateur est corrompue`);
    caller.router.navigate(['/login']);
    return false;
  }
}

2条回答
Rolldiameter
2楼-- · 2019-08-21 08:21

You don't want to define your lazy loaded modules' sub routes in your main loggedRoutes const. You should only define an entry point to the module, and then let the module handle its interior routing. By defining your modules' sub routes in loggedRoutes you've actually declared that they're part of your root app module.

canLoad is only for use with a lazy loaded module - and those modules must control their own routing. The root module cannot control this because then it would know about the lazy loaded module's components, and it wouldn't be lazy loaded.

Remove this from your loggedRoutes:

...adminRoutes,
...pilotageRoutes,
...suiviProdRoutes,

...mainRoutes is fine as it isn't part of a lazy loaded module.

and ensure your lazy loaded modules have their routes registered:

@NgModule({
  imports: [ RouterModule.forChild(adminRoutes) ]
})
export class AdminModule { }

The lazy loaded modules want to handle their own routing internally, as you're registering all routes at the top level your app does not care about the lazy loaded modules, it will see your admin routes and navigate you there because it's just a normal route. The AOT compiler will see your loadChildrens, however, and it will chunk up your code for you, but your main chunk containing your app will ALSO contain all the extra modules that are supposed to be lazy loaded.

You should also drop the name of the first route from your adminRoutes:

path: 'admin', component: AdminComponent...

Should become

path: '', component: AdminComponent...

The route segment admin is already provided by your module being registered as admin in the main loggedRoutes.

查看更多
干净又极端
3楼-- · 2019-08-21 08:26

There may be a problem with your canActivate. Here is the method body:

return canActivate(route, state, this, [global.roles.admin]);

It is calling another function called canActivate. What's that?

查看更多
登录 后发表回答