Reputation: 135
Hi Angular Developers,
Please I need your help, I need to block routing with specific roles, This is my Doc with profiles:
My angular guards return and object with profiles: {admin: true, current: false}
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class RoleGuard implements CanActivate {
constructor(
public authService: AuthService,
public router: Router
) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<any> | boolean {
return this.authService.getAuthWithProfile().pipe(
map((data) => {
const roles = data.roles;
return roles; // This returns {admin: true, current: false}
})
);
}
}
The question is How implement the guard for Roles in the Angular Routing, for example:
{ path: 'tasks', component: TasksComponent, canActivate: [RoleGuard] },
Upvotes: 0
Views: 756
Reputation: 38807
One approach is using data
property of Route. You can attach custom values to any given route. In your example you could create a property called roles
that can be used in your canActivate()
. In the following example an array of roles is added to the route for TasksComponent. In the guard we can extract roles
from next.data.roles
then check that the roles returning from Firebase are present and active:
Route:
{
path: 'tasks',
component: TasksComponent,
data: {
roles: ['admin', 'subscriber']
}
canActivate: [RoleGuard]
}
Guard:
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | boolean {
const routeRoles = next.data && next.data.roles; // ['admin', 'subscriber']
return this.authService.getAuthWithProfile().pipe(
map((data) => {
const roles = data.roles; // { admin: true, current: false }
const activeRoles = Object.entries(roles).filter(([role, isActive]) => isActive).map(([role, isActive]) => role); // ['admin']
return routeRoles.some(routeRole => activeRoles.includes(routeRole)); // true
})
);
}
}
data.roles
on the route does not have to be an array, it can instead be an object and you can approach checking the existence of the activated route in whatever fashion you are comfortable with. For example, if there is just a single role:
{
path: 'tasks',
component: TasksComponent,
data: {
role: 'admin'
}
canActivate: [RoleGuard]
}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | boolean {
const routeRole = next.data && next.data.role; // 'admin'
return this.authService.getAuthWithProfile().pipe(
map((data) => {
const roles = data.roles; // { admin: true, current: false }
const activeRoles = Object.entries(roles).filter(([role, isActive]) => isActive).map(([role, isActive]) => role); // ['admin']
return routeRoles.includes(routeRole); // true
})
);
}
}
Hopefully that helps!
Upvotes: 1