I currently have a home page that routes to all the different workflows my company runs. We have about 15 different workflows and each workflow is guarded by a user role. If you don't have the correct user role in the database you wont see corresponding link to that page. We protect the server end points, but what I am worried about is what is the best way to show people the links or not show them I would prefer to not duplicate code.
Here is one way to do it:
I have a html page like this
<ul>
<li *ngIf="authService.hasRequiredRole('users.user-admin')" routerLink="/user">Users</li>
<li *ngIf="authService.hasRequiredRole('users.role-admin')" routerLink="/role">Roles</li>
</ul>
I have an auth service like this:
hasRequiredRole(roles: string | [string]) {
if (typeof roles === 'string') {
roles = [roles];
}
for (const roleSlug of roles) {
if (this.user.roles.find((role: any) => {
return role.slug === roleSlug;
})) {
return true;
}
}
return false;
}
and I have a router with routes like this:
const routes: Routes = [{
path: 'user',
data: {
allowedRoles: 'users.user-admin'
},
loadChildren: 'app/user/user.module#UserModule',
canActivate: [AuthGuard]
},
{ path: 'home', component: HomeComponent }]
The AuthGuard just checks if the user is logged in and then uses the data in the route to check if the user has the correct role.
As you can see there are two separate locations where we use the string 'users.user-admin'.
I think we should have a router with two guards. One guard will check if the user is logged in, and another to check if the user has the correct role. The role will be hard coded there like this:
export class UserAdminGuard implements CanActivate {
constructor(private router: Router, private authService: AuthService) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable < boolean > | Promise < boolean > | boolean {
return this.authService.hasRequiredRole('users.user-admin');
}
}
and then the html would look something like this:
<ul>
<li *ngIf="userAdminGuard.canActivate()" routerLink="/user">Users</li>
<li *ngIf="roleAdminGuard.canActivate()" routerLink="/role">Roles</li>
</ul>
Would something like my method work or is there a better more angular way of doing this? I could not find anything in the documentation about anything like this. If you could also provide documentation extra points.
[string]
(anArray
of length exactly 1 containing astring
) or ratherstring[]
orArray<string>
? I ask because, while perfectly permissible, I have never seen it in production Angular. – Aliphaticstring[]
orArray<string>
.[string]
, on the other hand, is a tuple type, which means you declare the only valid type is an array of exactly the form you define. In this case, an array of length exactly 1 with 1 string (see link in original comment). Similarly, you could declare something likex: [string, number, number]
for which["a", 1, 2]
is valid, but["a", "b", "c"]
is not. – Aliphatic