Trying to understand the differences between CanActivate and CanActivateChild
Asked Answered
S

4

14

So, I'm trying to protect the access to several routes by using guards. I'm using the following routes to do so :

const adminRoutes : Routes = [
  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [ AuthGuardService ],
    children : [
      {
        path: '',
        canActivateChild: [ AuthGuardService ],
        children: [
          { path: 'edit', component: DashboardComponent},
          { path: '', component: DashboardComponent}
        ]
      }
    ]
  }
];

Here's a look at what AuthGuardService looks like

import { Injectable } from '@angular/core';
import {CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot} from "@angular/router";

@Injectable()
export class AuthGuardService implements CanActivate{

  constructor(private router: Router) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot){
    console.log("Guarding...");
    return this.sessionValid();
  }

  canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot){
    console.log("Guarding children...");
    return this.canActivate(route, state);
  }

  sessionValid() : boolean {
    //tests
  }

}

When I try to access to '/admin' and '/admin/edit' with canActivate only (canActivateChild is commented) the console displays

Guarding...

When I remove canActivateand bring canActivateChildback the console displays

Guarding children...

When I keep both, it goes back to displaying Guarding.... So, my question is what's the purpose of having canActivateChild when canActivateprotects both the root element and the children ?

PS : I get it that canActivateChild runs before the child route is activated. But what are the benefits of that ? Isn't keeping only one of them sufficient ?

Selfabnegation answered 6/3, 2017 at 17:41 Comment(0)
C
25

Both are important because you may have differing requirements where a user can get to the root component, but may not meet conditions for child components.

Example: You could have a situation where a user must be authenticated to navigate to the root component, but must have permission 'x' to get to child components. In cases like this, canActivateChild saves a lot of typing from having to add canActivate guards to each of the children.

EDIT:

For example, you may have an Admin Module where all routes need to be guarded against unauthorized entry:

  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [ AuthGuardService ],
    children : [
      {
        path: '', component: ...,
      },
      {
        path: 'manage-users', component: ...,
      },
      {
        path: 'manage-roles', component: ...,
      }
    ]
  }

This would need to be protected from the top down. No unauthorized access to any of the routes, including the root and children. In this situation canActivate at the root level works great to protect everything.

But you may also have times where you have a Feature module where only certain children need to be guarded:

  {
    path: 'featureA',
    component: ...,
    canActivateChild: [ AuthGuardService ],
    children : [
      {
        path: 'manage-feature', component: ...,
      },
      {
        path: 'manage-members', component: ...,
      }
    ],
    {path: 'featureB', component: ...}
  }

In this situation, maybe all users need to get to the root components 'featureA' and 'featureB', but only certain users need to be able to navigate to the child routes of 'featureA'. In this case it is easier to use one guard at the root level to protect the children, but not the root itself. The alternative is to put canActivate guards on each child route, which could get tedious.

It really all depends upon your requirements, but it can be nice to have both options of canActivate and canActivateChild.

Cupric answered 6/3, 2017 at 17:53 Comment(2)
Can't we just use canActivate instead of canActivateChild then ?Selfabnegation
Maybe, it depends on your requirements. The example I gave above may be a bit too contrived. canActivateChild is run before each child route is activated. You can indeed protect a root component an all children with canActivate, but you may have children certain users don't need to see when they need to be able to see the root component. For example, you could sprinkle in some Admin components into a Feature module that most or all users need to get to the root of, but not necessarily children of certain routes.Cupric
P
2

In my view, the CanActivate is used to restrict access from a certain path and all the sub-paths and CanActivateChild is used to restrict access to a specific group inside the CanActivate path.

Example:

{
  path: 'admin',
  component: AdminComponent,
  canActivate: [AuthGuardService],
  children : [
    {
      path: 'books', component: ...,
    },
    {
      path: 'authors', component: ...,
    },
    {
      path: 'payments',
      canActivateChild: [AuthGuardService],
      children: [
        {
          path: 'list', component: ...
        },
        {
          path: 'list/:id', component: ...
        }
      ]
    }
  ]
}

Because you need two types of validations, you cannot have two canActivate methods, so you need the canActivateChild for checking the permision inside the canActivate path. Obviously, you can create a different guard service (AuthGuardForChildrenRoutes) and still use canActivate method, but that's not the point.

Pediatrician answered 13/10, 2017 at 12:1 Comment(0)
P
1
sr no. CanActivate CanActivateChild
1 It prevents access to the parent route which also includes access to all child routes we can access the parent route but if required we can choose to block a particular child route by using canActivateChild
2 Yes you can achieve CanActivateChild behavior by applying CanActivate to all the child routes just adding CanActivateChild at parent route saves a lot of time and it is more convenient

Now this was the basic difference between canActivate and canActivatedchild
here is the situation where these two could be used


Figure : path to illustrate the difference between CanActivate & CanActivateChild
canactivatedchild vs canactive example

CanActivate: Computer department student can not access other departments
CanActivateChild: Computer department student have access to computer department(which is parent in this case) but cannot access one child of computer department i.e. faculty role access

Pahl answered 12/5, 2021 at 9:21 Comment(0)
U
0

In your example you have called canActivate inside canActivateChild, hence both the guards are getting called when you are traversing among child routes. If you were to have different authentication logic inside both the guards, your canActivate guard won't execute while traversing among child routes.

Unsex answered 10/3, 2019 at 15:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.