9
votes

What is the best way to implement ACL / paper-based with angular 2?

My scenario, in a nutshell, is this: The roles are dynamic and are based on the permissions that the client can configure that can also be dynamic.

I need to prevent the user from having access to a particular resource that he is not authorized to do. For this I thought of using the concept of Guards of the Angular. With CanActivate Guard I could set whether to let the user pass or not, based on information I would put in each route. This information would be the name of the resource to which that route refers. When I got to the guard I could compare with his role and see if his role has access to this feature and whether or not to allow navigation.

But with that in could fall into two more problems:

1 - How to redirect the user to a resource that he has access to? Would I have to list the route files and look for someone who is compatible with his role and then redirect there?

2 - How to disable components that it can not see on pages that it can access? For example, it has access to the listing page X but it does not have access to create a new item, so I need to remove the Create Something button. Or rather, how to do this with divs elements that contains specific information for some roles but not for the role of it?

I would like to know how best to approach this scenario within the angular ecosystem.

Thanks for listening.

2
Caveat: Angular 2 puts everything on the client, so "protecting" a resource that is in Angular (ie: secret keys, or data object) is not possible, you have to do that at the data source. So what you are really looking at is hiding/showing visual components and redirecting, here: [Hiding Menu Items (could be extended to buttons, data objects, etc)] (stackoverflow.com/questions/36041192/…) [Redirecting] (stackoverflow.com/questions/32896407/…). We pull ACL from data source.davmor
I'm not sure if you have figured out the solution to your issue yet. However I would like to note that the link @davmor provided for [Hiding Menu items] is outdated, since the it uses the old router which is deprecated. With the current Router, no way to get the route data until ActivatedRoute injected... after that then you can access it's data.penleychan

2 Answers

4
votes

You can try to use ngx-permissions library for this. It supports, then, else syntax, lazy loading, isolated lazy loading. Add the library to the project:

@NgModule({

 imports: [
    NgxPermissionsModule.forRoot()
 ] 
 })
 export class AppModule { }

Load Roles

NgxRolesService
 .addRole('ROLE_NAME', ['permissionNameA', 'permissionNameB'])

 NgxRolesService.addRole('Guest', () => {
  return this.sessionService.checkSession().toPromise();
 }); 

 NgxRolesService.addRole('Guest', () => {
     return true;
 }); 

use in templates

<div *ngxPermissionsOnly="['ADMIN', 'GUEST']">
  <div>You can see this text congrats</div>
</div>

protect Your Guard

const appRoutes: Routes = [
 { path: 'home',
component: HomeComponent,
canActivate: [NgxPermissionsGuard],
data: {
  permissions: {
    only: ['ADMIN', 'MODERATOR'],
    except: ['GUEST']
   }
  }
 },
];

For detail documentation checkout wiki page.

3
votes

Check CASL, there are articles about integration in Vue and Aurelia but for Angular 2+ implementation should be very similar

The main idea that you can define abilities per user

import { AbilityBuilder } from 'casl'


// allow to read and create Todo-s for everybody and update for assignees
export default AbilityBuilder.define(can => {
  can(['read','create'], 'Todo')
  can(['update'], 'Todo', { assignee: user.id })
})

There is also an article in documentation about how to map abilities to different roles