admin管理员组

文章数量:1305899

I'm encountering a strange behaviour (or maybe a wanted one). I have an Angular application where all the modules are lazy loaded.

On one module I have a guard that checks if the decoded user from the JWT is a system admin. If so, the user shall proceed to the section, otherwise it will be redirected in dashboard.

The strange thing is that this thing works only upon the first module load. Then, if I try to logout and access with a user that is not as system admin, the CanLoad guard does not trigger.

I've also tried to implement in the same guard the (CanActivate and CanActivateChild) interfaces, and put the guard on the app-routing.module.ts and on the feature-routing.module.ts modules, respectively on the CanLoad, CanActivate, and CanActivateChild properties of the modules.

The CanActivate CanActivateChild methods never gets called. Never.

While the CanLoad placed on the app-routing.module.ts is called just once.

Here's the is-sys-adm.guard.ts file:

export class SFWIsSysAdmGuard implements CanLoad, CanActivate, CanActivateChild {

        public constructor(
            private readonly accessSvc: SFWAuthService,
            private readonly toastSvc: NbToastrService,
            private readonly translateSvc: TranslateService,
            private readonly navigationSvc: NavigationService,
        ) { }


        public canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
            console.log('Can activate child hit');
            return this.canLoad(undefined, undefined);
        }

        public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
            console.log('Can activate hit');
            return this.canLoad(undefined, undefined);
        }

        public canLoad(route: Route, segments: UrlSegment[]): boolean {
            console.log('Can load hit');
            const decodedUser = this.accessSvc.decodedUser;
            if (!!decodedUser && !!decodedUser.isSystemAdmin) {
                return true;
            }

            this.navigationSvc.goToDashboard();
            this.toastSvc.warning(
                this.translateSvc.instant('framework.guards.adm_only.access_denied'),
                this.translateSvc.instant('mon.access_to_section_denied_ttl'),
            );
            return false;
        }
    }

Here's the app-routing.module.ts file:

const routes: Routes = [
        {
            path: '',
            redirectTo: `/${AppRoutes.access}`,
            pathMatch: 'full'
        },
        {
            path: AppRoutes.dashboard,
            loadChildren: () => import('./dashboard/dashboard.module').then(mod => mod.DashboardModule)
        },
        {
            path: AppRoutes.pins,
            loadChildren: () => import('./pins/pins.module').then(mod => mod.PinsModule)
        },
        {
            path: AppRoutes.pinTypes,
            loadChildren: () => import('./pin-types/pin-types.module').then(mod => mod.PinTypesModule)
        },
        {
            path: AppRoutesanizationPickup,
            loadChildren: () => import('./organization-picker/organization-picker.module').then(mod => mod.OrganizationPickerModule)
        },
        {
            path: AppRoutes.access,
            loadChildren: () => import('./access/access.module').then(mod => mod.AccessModule)
        },
        {
            path: AppRoutes.tourism,
            loadChildren: () => import('./tourism/tourism.module').then(mod => mod.TourismModule)
        },
        {
            path: AppRoutes.security,
            canLoad: [SFWIsSysAdmGuard],
            loadChildren: () => import('./security/security.module').then(mod => mod.SecurityModule)
        },
        {
            path: AppRoutes.notFound,
            loadChildren: () => import('./not-found/not-found.module').then(mod => mod.NotFoundModule)
        },
        {
            path: '**',
            redirectTo: '/404'
        }
    ];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule { }

Last but not least: feature-routing.module.ts file:

const routes: Routes = [
    {
        path: '',
        canActivate: [SFWIsSysAdmGuard],
        ponent: SecurityComponent,
        children: [
            {
                path: 'tokens-generator',
                canActivateChild: [SFWIsSysAdmGuard],
                ponent: TokensGeneratorComponent
            },
        ]
    }
];

@NgModule({
    imports: [RouterModule.forChild(routes)],
    exports: [RouterModule]
})
export class SecurityRoutingModule { }


@NgModule({
    imports: [RouterModule.forChild(routes)],
    exports: [RouterModule]
})
export class SecurityRoutingModule { }

Before you ask, I've also tried to put the guard separately in a CanActivate, CanActivateChild, CanLoad to try to prevent any conflict (which shouldn't exist if I've understand the docs.)

Am I missing something? Is is a wanted behaviour or should I open a bug on the official repo?

Thank to anyone willing to spend time on this <3

I'm encountering a strange behaviour (or maybe a wanted one). I have an Angular application where all the modules are lazy loaded.

On one module I have a guard that checks if the decoded user from the JWT is a system admin. If so, the user shall proceed to the section, otherwise it will be redirected in dashboard.

The strange thing is that this thing works only upon the first module load. Then, if I try to logout and access with a user that is not as system admin, the CanLoad guard does not trigger.

I've also tried to implement in the same guard the (CanActivate and CanActivateChild) interfaces, and put the guard on the app-routing.module.ts and on the feature-routing.module.ts modules, respectively on the CanLoad, CanActivate, and CanActivateChild properties of the modules.

The CanActivate CanActivateChild methods never gets called. Never.

While the CanLoad placed on the app-routing.module.ts is called just once.

Here's the is-sys-adm.guard.ts file:

export class SFWIsSysAdmGuard implements CanLoad, CanActivate, CanActivateChild {

        public constructor(
            private readonly accessSvc: SFWAuthService,
            private readonly toastSvc: NbToastrService,
            private readonly translateSvc: TranslateService,
            private readonly navigationSvc: NavigationService,
        ) { }


        public canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
            console.log('Can activate child hit');
            return this.canLoad(undefined, undefined);
        }

        public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
            console.log('Can activate hit');
            return this.canLoad(undefined, undefined);
        }

        public canLoad(route: Route, segments: UrlSegment[]): boolean {
            console.log('Can load hit');
            const decodedUser = this.accessSvc.decodedUser;
            if (!!decodedUser && !!decodedUser.isSystemAdmin) {
                return true;
            }

            this.navigationSvc.goToDashboard();
            this.toastSvc.warning(
                this.translateSvc.instant('framework.guards.adm_only.access_denied'),
                this.translateSvc.instant('mon.access_to_section_denied_ttl'),
            );
            return false;
        }
    }

Here's the app-routing.module.ts file:

const routes: Routes = [
        {
            path: '',
            redirectTo: `/${AppRoutes.access}`,
            pathMatch: 'full'
        },
        {
            path: AppRoutes.dashboard,
            loadChildren: () => import('./dashboard/dashboard.module').then(mod => mod.DashboardModule)
        },
        {
            path: AppRoutes.pins,
            loadChildren: () => import('./pins/pins.module').then(mod => mod.PinsModule)
        },
        {
            path: AppRoutes.pinTypes,
            loadChildren: () => import('./pin-types/pin-types.module').then(mod => mod.PinTypesModule)
        },
        {
            path: AppRoutesanizationPickup,
            loadChildren: () => import('./organization-picker/organization-picker.module').then(mod => mod.OrganizationPickerModule)
        },
        {
            path: AppRoutes.access,
            loadChildren: () => import('./access/access.module').then(mod => mod.AccessModule)
        },
        {
            path: AppRoutes.tourism,
            loadChildren: () => import('./tourism/tourism.module').then(mod => mod.TourismModule)
        },
        {
            path: AppRoutes.security,
            canLoad: [SFWIsSysAdmGuard],
            loadChildren: () => import('./security/security.module').then(mod => mod.SecurityModule)
        },
        {
            path: AppRoutes.notFound,
            loadChildren: () => import('./not-found/not-found.module').then(mod => mod.NotFoundModule)
        },
        {
            path: '**',
            redirectTo: '/404'
        }
    ];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule { }

Last but not least: feature-routing.module.ts file:

const routes: Routes = [
    {
        path: '',
        canActivate: [SFWIsSysAdmGuard],
        ponent: SecurityComponent,
        children: [
            {
                path: 'tokens-generator',
                canActivateChild: [SFWIsSysAdmGuard],
                ponent: TokensGeneratorComponent
            },
        ]
    }
];

@NgModule({
    imports: [RouterModule.forChild(routes)],
    exports: [RouterModule]
})
export class SecurityRoutingModule { }


@NgModule({
    imports: [RouterModule.forChild(routes)],
    exports: [RouterModule]
})
export class SecurityRoutingModule { }

Before you ask, I've also tried to put the guard separately in a CanActivate, CanActivateChild, CanLoad to try to prevent any conflict (which shouldn't exist if I've understand the docs.)

Am I missing something? Is is a wanted behaviour or should I open a bug on the official repo?

Thank to anyone willing to spend time on this <3

Share Improve this question asked Aug 29, 2019 at 9:51 CaiusCaius 2,2647 gold badges34 silver badges53 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 10

The CanLoad determines whether the lazy module can be loaded from the server. After it has been loaded, this will not be checked again (unless you press F5). I guess you need to declare it twice, once in CanLoad (if you don't want the code to be loaded at all), and CanActivate, if you want to restrict access.

{
  path: AppRoutes.security,
  canLoad: [SFWIsSysAdmGuard],
  canActivate: [SFWIsSysAdmGuard],
  loadChildren: () => import('./security/security.module').then(mod => mod.SecurityModule)
},

本文标签: javascriptAngular CanLoad guard triggers only once upon first lazy loadStack Overflow