Angular 7 CanActivate Guards Failing over

743 Views Asked by At

I've got CanActivate guards on all my routes and they are failing over.

For instance, I have two guards:

export class AuthenticationGuard implements CanActivate {
    constructor(private as: AuthenticationService, private router: Router) { }

    canActivate() {
        if (this.as.isLoggedIn()) {
            return true;
        }

        this.router.navigate(['/login']);

        return false;
     }
    }

export class IsAdminGuard implements CanActivate {
    constructor(private us: UserService, private router: Router) { }

    canActivate() {
        if (this.us.isAdmin()) {
            return true;
        }

        this.router.navigate(['/home']);

        return false;
    }
}

And my route guards

const routes: Routes = [
    {
        path: 'home',
        component: DashboardComponent,
        canActivate: [AuthenticationGuard, IsAdminGuard]
    }
];

@NgModule({
    imports: [ RouterModule.forRoot(routes) ],
    exports: [ RouterModule ]
});

What's happening is that if AuthenticationGuard fails, it will sometimes check IsAdminGuard and instead of routing someone to /login when they are not authenticated, they are sent to /home which sends them to a different error page because they are not authenticated and are not an admin and the guards should have kicked them out on the first fail.

I can reproduce the issue 100% of the time if I remove the authentication jwt that AuthenticationService checks when it calls isLoggedIn(), refresh the /home route and can trace the AuthenticationGuard returning false and still calling IsAdminGuard

Here is the code for isLoggedIn()

isLoggedIn = () => {
    const token = this.get();
    const decoded = this.decode(token);

    return token && this.isNotExpired(decoded);
};  

decode = (token: string) => {
    const validToken = () => parts.length < 3
    const parts = token ? token.split('.') : '';

    if (!token || validToken()) {
        return '{}';
    }

    const payload = validToken() ? parts[1] : '{}';

    return JSON.parse(atob(payload));
};

private isNotExpired = (decodedToken) => this.getExpiryFrom(decodedToken) > new Date();

private getExpiryFrom = (decodedToken) => new Date(decodedToken.exp * 1000);

thoughts?

1

There are 1 best solutions below

1
On

Consider working in a short circuit to your isAdmin guard that rechecks the authentication status. That way the authentication truthiness will never be overridden by how your isAdmin truthiness turns out. It may seem redundant, but it would work.