Angular permissions based on roles | Part 1. Roles, permissions and Permission Manager
Tags: angular, typescript, javascript, architecture
Published: 2023-09-03 17:10:26

---
title: Angular permissions based on roles | Part 1. Roles, permissions and Permission Manager
published: true
date: 2018-08-20 14:48:45 UTC
tags: angular,typescript,javascript,architecture
canonical_url: 
---

![](https://cdn-images-1.medium.com/max/1004/1*yciHIi5RKV7LAPqeSgngDA.png)

One of the biggest challenges we face when building Angular applications is the control and management of user permissions.  
Many times, we must show components or allow actions depending on the type of user.  
In this article, a proposed solution to this problem will be explained:

## Glossary:  
1. Define roles and permissions  
2. Build classes for the management of permissions of each user  
3. Service for the management of permissions  
4. Directive for the easy use of permissions management  
5. Stackblitz demo implementation_

## 1. Define roles and permissions

The first thing we have to define are the types of roles that our application will handle:

```ts
export enum Role {
  SUPERUSER = 'su',
  ADMIN = 'admin',
  USER = 'user',
  UNKNOWN = 'unknown'
}
```

The next step is to define the different permissions that we want to grant to users:

```ts
export enum PermissionType {
  CREATE = 'CREATE',
  READ = 'READ',
  UPDATE = 'UPDATE',
  DELETE = 'DELETE',
  OTHER = 'OTHER'
}
```

## 2. Build classes for the management of permissions of each user

Once the structure of our roles and permissions has been defined, we will implement the **base class for the permissions** of each type of user.

```ts
import { PermissionType } from '../permission-type';

export abstract class PermissionBase {
  public permissions: PermissionType[];
  constructor() {}
}
```

The next step will be to extend the base class for each type of user.

For example, for the **superuser** role who is granted for CREAD, READ, UPDATE, DELETE and OTHER actions:

```ts
import { PermissionType } from '../permission-type';
import { PermissionBase } from './base.permissions';

export class SuperuserPermission extends PermissionBase {

  constructor() {
    super();
    this.permissions = [  
      PermissionType.CREATE, PermissionType.READ,   
      PermissionType.UPDATE, PermissionType.DELETE,  
      PermissionType.OTHER  
    ];  
  }
}
```

After defining the permissions for each type of user, we will build a factory to build the instance of the class of permissions.By using the singleton pattern, we will limit to a single instance to prevent multiple instances of the permission handler.

```ts
import { PermissionBase } from './base.permissions';
import { Role } from '../role';
import { SuperuserPermission } from './superuser.permissions';
import { AdminPermission } from './admin.permissions';
import { UserPermission } from './user.permissions';
import { UnknownPermission } from './unknown.permissions';

export class PermissionsFactory {

  public static instance: PermissionBase;
  private constructor() {}

  public static getInstance() {
    if (this.instance) {
      return this.instance;
    } else {
      const role = localStorage.getItem('role');
      switch(role) {
        case Role.SUPERUSER:
          this.instance = new SuperuserPermission();
          break;
        case Role.UNKNOWN:
          this.instance = new UnknownPermission();
          break;
        . . .
        default:  
          this.instance = new UnknownPermission();
          break;
      }
    }
  }
}
```

## 3. Service for the management of permissions

For now, we have built our permissions for each user and a permission factory to obtain the instance. However, we need an accessible way to determine whether or not a user can perform a specific action.  
To solve this problem, we will implement a **global service** that makes use of our permission instance. In this way, it will be **accessible from any component or directive** of our application.

```ts
import { Injectable } from '@angular/core';
import { PermissionType } from './permission-type';
import { Role } from './role';
import { EnumValues } from 'enum-values';
import { PermissionBase } from './permissions/base.permissions';
import { PermissionsFactory } from './permissions/factory.permissions';

@Injectable(  
 provideIn: 'root'
)  
export class PermissionManagerService {

  private permissions: PermissionBase;
  constructor() { }

  isGranted (permission: PermissionType) {
    const permissions = PermissionsFactory.getInstance().permissions;
    for (let perm of permissions) {  
      if (perm === permission){  
        return true;  
      }  
    }  
    return false;
  }

  authAs (role: Role) {
    localStorage.setItem('role',
      (role === null)
        ? Role.UNKNOWN
        : role
    );
    this.permissions = PermissionsFactory.getInstance();
  }
}
```

- isGranted method receives a permission type as parameter, iterates the user’s permissions and returns true if found.
- authAs method demand a permission manager instance.

## 4. Directive for the easy use of permissions management

Now, PermissionManagerService can be consumed easily. However, we can make it even easier to use the service in the templates by creating a directive that consumes it:

```ts
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
import { PermissionType } from './permission-type';
import { PermissionManagerService } from './permission-manager.service';

@Directive({  
 selector: '[appIsGranted]'  
})  
export class IsGrantedDirective {
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private permissionManagerS: PermissionManagerService
  ) { }

  @Input() set appIsGranted(permission: PermissionType) {
    this.isGranted(permission);
  }

  private isGranted(permission: PermissionType) {
    if (this.permissionManagerS.isGranted(permission)) {  
      this.viewContainer.createEmbeddedView(this.templateRef);  
    } else {  
      this.viewContainer.clear();  
    }
  }
}
```

_Note that appIsGranted Directive is it is an *overwrite* of the ngIf directive implementation._

Directive usage:

```html
<div appIsGranted="'CREATE'">
  // This block will only be shown to granted users
</div>

<my-component appIsGranted="'DELETE'">
  // This component will only be shown to granted users
</my-component>
```

## 5. Stackblitz demo implementation

[rjlopez-angular-permissions-part1 - StackBlitz](https://stackblitz.com/edit/rjlopez-angular-permissions-part1?embed=1&file=src/main.ts)

_Note that it is not an implementation for a real environment and contains mocked code and data._

_See_ [Angular permissions based on roles | Part 2. Permissions for multiple resources](https://medium.com/@rjlopezdev/angular-permissions-based-on-roles-part-2-permissions-for-multiple-resources-d35ea97df5b7)