Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a more comprehensive way to handle authentication in Angular2 rc3 than guards?

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.

like image 753
NColey Avatar asked Nov 09 '22 12:11

NColey


1 Answers

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.

like image 139
smyk Avatar answered Nov 15 '22 11:11

smyk