I know the subject has often been treated on StackOverflow.
I consulted several posts on Stack but the suggested solution doesn't work for me.
For exemple this one
I try for the first time to restrict access to pages by using Guards but it doesn't work for child pages.
I have a Truck module containing childs like that :
Truck
|_ truck-list
|_ truck-search
|_ truck-menu
|_ truck-details
I have a route file for the Truck module :
RouterModule.forChild([
{path: 'list', component: TruckListComponent, canActivate: [TruckGuard]},
{path: 'search', component: TruckSearchComponent, canActivate: [TruckGuard]},
{path: 'details/:id', component: TruckDetailsComponent},
{path: 'menu', component: TruckMenuListComponent},
{path: 'menu/:id', component: TruckMenuListComponent},
{path: 'menu/add/:id', component: TruckMenuAddComponent},
])
and an app-routing module :
const appRoutes: Routes = [
{ path: '', component: HomeComponent},
{ path: 'app-forbidden', component: ForbiddenComponent},
{ path: 'Home', component: HomeComponent},
{ path: 'About', component: AboutComponent},
{ path: 'forbidden', component: ForbiddenComponent},
{ path: 'Login', component: LoginComponent},
{ path: 'Logout', component: LoginComponent},
{ path: 'confirmation-commande/:message', component: ConfirmationCommandeComponent},
{ path: 'orders', component: OrderListComponent},
{ path: 'truck/search', component: TruckSearchComponent},
{ path: 'SignUp/customer', component: UseraccountCreateCustomerComponent},
{ path: 'SignUp/truck', component: UseraccountCreateTruckComponent},
{ path: 'useraccount', loadChildren: () => import('./useraccount/useraccount.module').then(u => u.UserAccountModule)},
{ path: 'truck', loadChildren: () => import('./truck/truck.module').then(t => t.TruckModule)},
{path: 'location', component: TruckLocationComponent},
{ path: '500', component: InternalServerComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' }
];
...
I also created a Truck.guard.ts file to manage route for the truck module :
export class TruckGuard implements CanActivate, CanActivateChild {
constructor(private authService: AuthService, private route: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let url = window.location.pathname;
if((url == '/truck') && this.authService.isCustomer()){
return true;
}
else{
this.route.navigate(['app-forbidden']);
return false;
}
}
canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let url = window.location.pathname;
if((url == '/truck/list') && this.authService.isCustomer()){
return true;
}
else if((url == '/truck/search') && this.authService.isCustomer()){
return true;
}
else if((url == '/Login') && this.authService.isCustomer()){
return true;
}
else{
this.route.navigate(['app-forbidden']);
return false;
}
}
}
The only path that works is truck/list
. He is well redirected to forbbiden page.
All the others doesn't work.
I don't understand why. Howver I use canActivate and canActivateChild.
Thanks in advence for your help.
CodePudding user response:
You are doing a couple of things wrong.
The reason truck/list works is because you are applying canActivate on it and not the rest here
{path: 'list', component: TruckListComponent, canActivate: [TruckGuard]},
and in your canActivate you are only catering for truck/list here
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let url = window.location.pathname;
if((url == '/truck') && this.authService.isCustomer()){
return true;
}
else{
this.route.navigate(['app-forbidden']);
return false;
}
}
- The reason why others are not working is because you are not applying canActivateChild to the parent module.
add a canActivateChild to the appRoute like this
const appRoutes: Routes = [
{ path: '', component: HomeComponent},
{ path: 'app-forbidden', component: ForbiddenComponent},
{ path: 'Home', component: HomeComponent},
{ path: 'About', component: AboutComponent},
{ path: 'forbidden', component: ForbiddenComponent},
{ path: 'Login', component: LoginComponent},
{ path: 'Logout', component: LoginComponent},
{ path: 'confirmation-commande/:message', component: ConfirmationCommandeComponent},
{ path: 'orders', component: OrderListComponent},
{ path: 'truck/search', component: TruckSearchComponent},
{ path: 'SignUp/customer', component: UseraccountCreateCustomerComponent},
{ path: 'SignUp/truck', component: UseraccountCreateTruckComponent},
{ path: 'useraccount', loadChildren: () =>
import('./useraccount/useraccount.module').then(u => u.UserAccountModule)},
// Truck module Your canActivateChild comes here
{ path: 'truck', loadChildren: () => import('./truck/truck.module').then(t=> t.TruckModule)}, canActivateChild:TruckGuard // <<< HERE
{path: 'location', component: TruckLocationComponent},
{ path: '500', component: InternalServerComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' }
];
CodePudding user response:
Finaly the solution is to add canActivateChild in the app-module.ts:
{ path: 'truck', loadChildren: () => import('./truck/truck.module').then(t => t.TruckModule), canActivateChild: [TruckGuard]},
and test url in the guard file using state: RouterStateSnapshot
in place of window.location.pathname
like this :
if((state.url == '/truck/list') && this.authService.isCustomer()){
return true;
}
else if((state.url == '/truck/search') && this.authService.isCustomer()){
return true;
}
else if((state.url == '/truck/menu') && this.authService.isCustomer()){
return true;
}
else if((state.url == '/truck/menu/' childRoute.params['id']) && this.authService.isCustomer()){
return true;
}
else if((state.url == '/truck/details/' childRoute.params['id']) && this.authService.isCustomer()){
return true;
}
else if((state.url == '/Login') && this.authService.isCustomer()){
return true;
}
else{
this.route.navigate(['app-forbidden']);
return false;
}