← Volver al blog
3 min de lecturaArquitectura

Permisos en Angular por roles | Parte 2. Varios recursos

Segunda parte: permisos por recurso y por tipo de acción, ampliando el Permission Manager de la primera entrega.

En el artículo anterior implementamos un manejador de roles y permisos, un servicio global para consumirlo y una directiva para usarlo con facilidad.

En este artículo nos centramos en gestionar permisos distintos para cada recurso de la aplicación.

Por ejemplo, un USER puede READ y ORDER pizza, pero solo puede READ pedidos.

Glosario:

  1. Definir el modelo Permission
  2. Refactorizar (PermissionBase y sus clases hijas)
  3. Refactorizar (servicio): isGranted ahora controla permisos y recursos
  4. Refactorizar (directiva): ahora recibe recurso y permiso como parámetros
  5. Demo en StackBlitz

1. Definir el modelo Permission

Necesitamos una estructura de datos que relacione recursos con permisos. Primero definimos los recursos que manejará la aplicación.

export enum Resource {
  PASTA = 'PASTA',
  PIZZA = 'PIZZA',
  BILL = 'BILL'
}

Una vez definidos los recursos, definimos la estructura del permiso:

import { Resource } from './resource';
import { PermissionType } from './permission-type';

export class Permission {
  public resource: Resource;
  public permissions: PermissionType[];

  constructor(resource: Resource, permissions: PermissionType[]) {
    this.resource = resource;
    this.permissions = permissions;
  }
}

Cada permiso agrupa una lista de acciones permitidas por recurso y usuario.

2. Refactorizar (PermissionBase y clases extendidas)

Adaptamos PermissionBase al nuevo modelo de permisos.

import { Permission } from '../permission';

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

Ahora las clases hijas definen permisos por recurso:

import { PermissionType } from '../permission-type';
import { Resource } from '../resource';
import { PermissionBase } from './base.permissions';
import {Permission } from '../permission';

export class UserPermission extends PermissionBase {
  constructor() {
    super();
    this.permissions = [
      new Permission(Resource.BILL, [
        PermissionType.READ,
        PermissionType.ORDER
      ]),
      new Permission(Resource.PASTA, [
        PermissionType.READ,
        PermissionType.ORDER
      ]),
      new Permission(Resource.PIZZA, [
        PermissionType.READ,
        PermissionType.ORDER
      ])
    ];
  }
}

3. Refactorizar (servicio): isGranted con recurso y permiso

¡Refactorizamos!

isGranted(resource: Resource, permission: PermissionType) {
  for (const res of this.permissions.permissions) {
    if (resource == res.resource) {
      for (const perm of res.permissions) {
        if (perm == permission) {
          return true;
        }
      }
    }
  }
  return false;
}

4. Refactorizar (directiva): recurso y permiso como parámetros

Adaptamos la directiva para recibir un Input compuesto por recurso y tipo de permiso.

@Input() set appIsGranted(permission: Array<string>) {  
  this.isGranted(  
    permission[0] as Resource,  
    permission[1] as PermissionType  
  );  
}

private isGranted(resource: Resource, permissionType: PermissionType) {
  if (this.permissionManagerS.isGranted(resource, permissionType)) {
    this.viewContainer.createEmbeddedView(this.templateRef);
  } else {
    this.viewContainer.clear();
  }
}

Uso:

<div *appIsGranted="['PIZZA', 'CREATE']">
  // This block will only be shown to granted users
</div>

<my-component *appIsGranted="['PASTA', 'DELETE']">
  // This component will only be shown to granted users
</my-component>

5. Demo en StackBlitz

rjlopez-angular-permissions-part2 - StackBlitz


Publicado originalmente en dev.to.