Angular2: Global Guard (user has to be logged in always)

Benjamin M picture Benjamin M · Dec 19, 2016 · Viewed 9.3k times · Source

I'm building an application where there's no access at all for unauthenticated users.

I wrote a LoggedInGuard, but now I have to add canActivate: [LoggedInGuard] to every route inside my router configuration (except the LoginComponent).

Is there a better way to get this working?


My file / module layout looks like this:

app/
  AppModule
  AppRoutingModule
  AppComponent

  authentication/
    AuthenticationModule
    AuthenticationRoutingModule
    LoginComponent

  contacts/
    ContactsModule
    ContactsRoutingModule
    ContactListComponent

  users/
    UsersModule
    UsersRoutingModule
    UserEditComponent

  ...

Maybe it's possible to create two separate routing spaces (one for login, one for the rest of the app) and apply the guard only to the rest of the app part?


I hope there's a simple solution.

Thanks in advance!

Answer

wuno picture wuno · Dec 19, 2016

I think I do it in a much more logical way. I guess it is an opinion. I separate my application by secured pages and public pages. I use templates for each set. So public component and secure component then put the guard on the secure template.

Make sure you are adding [Guard] to the full route that is in need of protection.

So when I secure a route I add the parents to app.routing.ts

const APP_ROUTES: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full', },
    { path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
    { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];



export const routing = RouterModule.forRoot(APP_ROUTES);

Make sure this line is noticed,

 { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }

So I create 2 layouts

/public/ all public components

/public/public.routes.ts

/secure/ all secure components

/secure/secure.routes.ts

Secure routes

Notice that these routes do not need Guard now because it is handled by the template parent.

export const SECURE_ROUTES: Routes = [
    { path: '', redirectTo: 'overview', pathMatch: 'full' },
    { path: 'items', component: ItemsComponent },
    { path: 'overview', component: OverviewComponent },
    { path: 'profile', component: ProfileComponent },
];

Main routes in app.routing.ts

const APP_ROUTES: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full', },
    { path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
    { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];

export const routing = RouterModule.forRoot(APP_ROUTES);

And in the directory /layouts I create a layout that is

/layouts/secure.component.ts

/layouts/secure.component.html

/layouts/public.component.ts

/layouts/public.component.html

Everything is routed through the layout public or secure and [Guard] is on secure.

Then I handle authentication with a token in the local storage.

@Injectable()
export class Guard implements CanActivate {

    constructor(protected router: Router, protected auth: Auth ) {}

     canActivate() {
        if (localStorage.getItem('access_token')) {
            // logged in so return true
            return true;
        }
        // not logged in so redirect to login page
        this.router.navigate(['/home']);
        return false;
    }
}

Once I set my app up like this I put all my routes that need to be secure in the secure directory and the public routes in public. Then I create their routes in the public.routes.ts file or the secure.routes.ts file which are in their respective directory.