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?
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.