3
votes

I am working on setting up AuthGuard for routes in an Angular 2 application. Each route has different user groups that can go to that route. On the front-end I am only storing a bearer token so when canActivate is called I want to call an API, send in my token and route, let the API resolve whether or not that user has access to that route and if they do, return a true, otherwise return a false. On the front-end, I want to use the results from that call to either route them or just send them back to the login screen.

This is how I am trying to accomplish that:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    this.authService.authenticateRouteForUser(state.url).subscribe(active => {
        if (active) {
            return true;
        }

        this.authService.redirectUrl = state.url;
        this.router.navigate(['/login-page'])
        return false;
    })
}

The logic within the subscribe works because I have tested it like this (This is essentially taken right from the Angular documentation by Google):

 canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean{
     console.log('AuthGuard#canActivate called')
     if(this.authService.isLoggedIn){
        return true;
     }

     this.authService.redirectUrl = state.url;

     this.router.navigate(['/login-page'])
     return false;
 }

I know that the problem with my first statement is that the canActivate has to return a true or a false and I am only returning a true or a false within the subscribe. The problem is I only want to return a true or a false after the route authentication has happened, which requires a call to the API. Am I approaching this all wrong? Should I just return user roles on login and store the roles for each route on the front-end so I can just check that without doing a call? Is there some other way to approach this that I am missing?

2

2 Answers

3
votes

Assuming your server returns a token which expires and has some roles. You would only need to check these in your guard. So simply store them in your localstorage or sessionstorage. For each server call you should provide the token, so if someone tampers with the localstorage your server should give an error. This way users might "hack" into routes they shouldn't be, but you server simply won't return any data because the token is invalid.

0
votes

Try like this:

canActivate(): Observable<boolean> | Promise<boolean> | boolean {
    return new Promise(res => {
        this.authService.authenticateRouteForUser(state.url).subscribe(
            (active ) => {
                if (active) {
                    res(true);
                } else {
                    this.router.navigate(['/login-page']);
                    res(false);
                }
            },
            (error) => {
                this.router.navigate(['/login-page']);
                res(false);
            }
        );
    });
}