Go to a route if at least one guard is active

1.2k Views Asked by At

The guards in Angular2 routing run in the order they are provided. But in the case of guards with observables, even if the first guard is true, angular ignores it, and only apply the result from the second guard's observable.

How can I solve this?

const mainRoutes: Routes = [
  {
  path: 'app',
  component:MainComponent,
  canActivate:[AuthGuard],
  children:[
     { path: 'dashboard',  component: DashboardComponent },
     { path: 'protectedRoute',  component: ProtectedRouteComponent, canActivate:[Admin1Guard,Admin2Guard] }
  ]}
];

The first guard:

canActivate() :Observable<boolean>{
    return this.authService.getUser().map(res=>{
        if(res.user.role=="admin1")
          return true;
      }).take(1);
   }
 }

The second guard:

canActivate() :Observable<boolean>{
    return this.authService.getUser().map(res=>{
        if(res.user.role=="admin2")
          return true;
      }).take(1);
    }
  }
1

There are 1 best solutions below

5
On BEST ANSWER

I would refactor the role-checking logic into a single, generic CheckRoleGuard service and attach the name of the role to check to the route via the data property:

{
  path: 'protectedRoute1',
  component: SomeComponent,
  canActivate: [CheckRoleGuard],
  data: { allowedRoles: ['admin','editor'] }
},
{
  path: 'protectedRoute2',
  component: SomeComponent,
  canActivate: [CheckRoleGuard],
  data: { allowedRoles: ['admin'] }
}

And now for the the RoleGuard service:

@Injectable()
class CheckRoleGuard {

  constructor(private authService: AuthService) { }

  canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
    // Retrieve the allowed roles from `route.data`.
    const allowedRoles = route.data['allowedRoles'];

    return this.authService.getUser()
      .map(data => {
        return allowedRoles.indexOf(data.user.role) !== -1;
      });
  }

}