5

I have an existing Angular2 app where login/authentication was handled by creating an AuthRouterOutletDirective that extended the RouterOutlet. This made it easy to use componentInstruction in the activate function to check if a user was logged in, if not redirect them to our login portal (for various reasons I have no control over this is through a separate app, which has it's own login screen and then sends back a token that we would save in the Angular2 app) before navigating to the next component.

I just upgraded to the router 3.0.0-alpha.8 and I see that this is no longer an option and it has been replaced by creating an authGuard and and using the canActivate method to handle authentication (I'm referring to this section of the documentation). The problem I'm struggling with is it seems like this is designed for apps where only a small number of routes are protected, and you can just add canActivate: [AuthGuard] to each route that requires authentication in the RouterConfig.

The problem I'm having is that every single route needs to be protected by authentication. There also needs to be continuous checking (unless there is a better fix) because we also (again due in part to the external login service we have to use) will log out the users and clear their token and the next time you navigate to a new route (regardless of what the route is) it should redirect you to login again. I understand that I could just add canActivate: [AuthGuard] to every single route but that seems like an insane and tedious fix, especially for apps with a large amount of routes, all of which require a user to be authenticated to view.

I've been searching for a fix but it seems like, perhaps in part because the upgrade is fairly new, that all the resources are for how to implement these AuthGuards on just one or two routes. I've been digging through the source code (specifically here) to see if there is another method I can extend that's more comprehensive than canActivate or a more universal way to have every route include a particular guard but I can't seem to find anything. Any advice on how best to implement this would be very much appreciated! Thanks.

NColey
  • 525
  • 1
  • 6
  • 18
  • RouteConfig is just an JS object. If you need to protect all paths with no exception, you can loop through it and set the guard. – smyk Jul 08 '16 at 18:56
  • @smyk Thanks for responding. Perhaps this is an obvious question but I can't quite figure out how to loop through and set the guard. I tried looping through the `appRoutes` `RouterConfig` constant after setting it but before passing it to the `provideRouter` function and I can't quite seem to figure out how to set that up. Do you by any chance have an example you could point me to? Thanks again! – NColey Jul 12 '16 at 14:21

1 Answers1

1

Referring to my comment, you can add extra guard like that:

import {provideRouter, RouterConfig, Route, CanActivate, ActivatedRouteSnapshot} from '@angular/router';
import {Injectable} from "@angular/core";

@Injectable()
class UniversalGuard implements CanActivate {
    canActivate(route: ActivatedRouteSnapshot) {
        console.log('applying can activate');
        return true;
    }
}

let routes: RouterConfig = [
    {path: 'path1', component: Component1} as Route,
    {path: 'path2', component: Component2} as Route,
    {path: 'path3', component: Component3} as Route
];

const routeAugumenter = route => {
    let guards = route.canActivate || [];
    guards.push(UniversalGuard);

    route.canActivate = guards;

    if (route.children) {
        route.children = route.children.map(routeAugumenter);
    }

    return route;
};

let augumentedRoutes = routes.map(routeAugumenter);

console.log(augumentedRoutes);

export const APP_ROUTER_PROVIDERS = [
    provideRouter(augumentedRoutes), UniversalGuard
];

I have not tested it with child routes, but should work as well.

Edit: updated information how to inject services into UniversalGuard.

If your guard needs some services injected, you inject them in the constructor, as usually. You have to provide these services (and the services they depend on, etc.) in Angular bootstrap call rather than in the components.

smyk
  • 346
  • 2
  • 8
  • thank you so much, this is incredibly helpful. I was having an impossible time working it out but it makes so much more sense laid out this way, thank you! – NColey Jul 13 '16 at 19:34