I have 2 guards, AuthGuard and AccessGuard in the application. AuthGuard protects all the pages as the name suggests and stores the session object in the GlobalService and AccessGuard depends on the some access data in session object stored by AuthGuard in GlobalService.
Problem arises when AuthGuard returns an Observable and then simultaneously AccessGuard executes to check for session object which has not yet arrived and the code breaks. Is there any other way I can restrict the execution of AccessGuard until the session object arrives or any other work around to break this race condition?
#Note I have not merged the AccessGuard logic to AuthGuard as only some of the routes need to be checked for access while all other needs authentication. For example, Accounts page and DB page are accessible to all but User Managements and Dashboard need external access parameters that come from session object
export const routes: Routes = [
{
path: 'login',
loadChildren: 'app/login/login.module#LoginModule',
},
{
path: 'logout',
loadChildren: 'app/logout/logout.module#LogoutModule',
},
{
path: 'forget',
loadChildren: 'app/forget/forget.module#ForgetModule',
},{
path: 'reset',
loadChildren: 'app/reset/reset.module#ResetModule',
},
path: 'pages',
component: Pages,
children: [
{ path: '', redirectTo: 'db', pathMatch: 'full' },
{ path: 'db', loadChildren: 'app/pages/db/db.module#DbModule' },
{ path: 'bi', loadChildren: 'app/pages/dashboard/dashboard.module#DashboardModule', canActivate:[AccessableGuard] },
{ path: 'account', loadChildren: 'app/pages/account/account.module#AccountModule' },
{ path: 'um', loadChildren: 'app/pages/um/um.module#UserManagementModule', canActivate:[AccessableGuard] },
],
canActivate: [AuthGuard]
}
];
export const routing: ModuleWithProviders = RouterModule.forChild(routes);
#EDIT: Adding the Guard Codes
AuthGuard:
canActivate(route:ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean{
return new Observable<boolean>( observer => {
this._dataService.callRestful('POST', params.SERVER.AUTH_URL + urls.AUTH.GET_SESSION).subscribe(
(accessData) => {
if (accessData['successful']) {
observer.next(true);
observer.complete();
console.log("done");
}
else {
observer.next(false);
observer.complete();
}
});
});
}
AccessableGuard:
canActivate(route:ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean{
if(this._dataService.getModulePermission(route.routeConfig.path.toUpperCase()) < 2){
return false;
}
return true;
}
#NOTE: _dataService is GlobalService that stores the Access Permissions from AuthGuard.
I chose a different path --- Nesting my guards and making them dependencies of each other.
I have a RequireAuthenticationGuard
and a RequirePermissionGuard
. For most routes they need to both run but there is a specific order I require.
The RequireAuthenticationGuard
depends on my authN services to check if the current session is authenticated.
The RequirePermissionGuard
depends on my authZ services to check if the current session is authorized for a route.
I add the RequireAuthenticationGuard
as a constructor dependency of RequirePermissionGuard
and only begin checking permissions if authentication has been determined.
require-authentication.guard.ts
constructor(
private userSessionSerivce: UserSessionService) {}
canActivate(
_route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Observable<boolean> {
return this.validateAuthentication(state.url);
}
require-permission.guard.ts
constructor(
private permissionService: PermissionService,
/**
* We use the RequireAuthenticationGuard internally
* since Angular does not provide ordered deterministic guard execution in route definitions
*
* We only check permissions once authentication state has been determined
*/
private requireAuthenticationGuard: RequireAuthenticatedGuard,
) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Observable<boolean> {
const requiredPermissions: Permission[] = next.data.permissions || [];
return this.requireAuthenticationGuard
.canActivate(next, state)
.pipe(
mapTo(this.validateAuthorization(state.url, requiredPermissions)),
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With