Authenticated users in my app can have several roles, therefore, I want to guard routes based on users' specific roles. I included roles checking in method checkAuthentication()
in AuthGuardService
, then apply data: { roles: ['USER'] }
in routing module. I also set identity
in store to detect roles for routing guard in AuthService
. However, when I tried to log in, it does not route to dashboard and just stay in log in page, even though I can see tokens set in local storage.
routing-module:
{
path: 'home', component: HomeComponent, canActivate: [AuthGuardService], data: { roles: ['PRIMARY, SUBSTITUTE'] },
children: [
{ path: '', redirectTo: 'offers', pathMatch: 'full' },
{ path: 'offers', component: OffersComponent, data: { roles: ['PRIMARY, SUBSTITUTE'] }, canActivateChild: [AuthGuardService] },
{ path: 'users', component: UsersComponent, data: { roles: ['PRIMARY'] }, canActivateChild: [AuthGuardService] },
{ path: 'settings', component: SettingsComponent, data: { roles: ['PRIMARY, SUBSTITUTE, USER'] },
canActivateChild: [AuthGuardService] }
]
}
auth-guard-service:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
const url: string = state.url;
return this.checkAuthentication(url, state, route.data['roles']);
}
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.canActivate(route, state);
}
checkAuthentication(url: string, state, requiredRoles: string[]) {
return this.authService.roles$.pipe(
flatMap((roles: string[]) => {
for (const role of requiredRoles) {
if (roles.includes(role) && this.authService.hasValidToken()) {
return of(true);
} else if (roles.includes(role) && this.authService.hasValidToken() === false) {
return this.authService.refreshToken().pipe(
map((tokens: AuthToken) => {
if (tokens.authToken) {
// refresh token successful
return true;
}
// refresh token did not succeed
this.authService.logout();
this.router.navigate(['']);
return false;
},
error => {
this.authService.logout();
this.router.navigate(['']);
return of(false);
})
);
}
}
this.router.navigate(['']);
return of(false);
})
);
}
auth-service:
private roles = new BehaviorSubject([]);
public roles$ = this.roles.asObservable();
private identity = new BehaviorSubject(<Identity>{});
public identity$ = this.identity.asObservable();
constructor(
private store: Store<AppState>
) {
this.store.select('tokens').subscribe((tokens: AuthToken) => {
this.tokens = tokens;
});
this.store.select('identity').subscribe((identity: any) => {
console.log(identity);
if (identity.identity && identity.identity.roles) {
this.setIdentity(identity.identity);
this.setRoles(identity.identity.roles);
} else {
this.setRoles([]);
}
});
}
setRoles(roles: any[]) {
this.roles.next(roles);
console.log(roles);
}
setIdentity(identity: Identity) {
this.identity.next(identity);
console.log(identity);
}