Limitar el acceso según el rol, creando un permiso y usando un hook

drupal 8  logo.jpg
Solucionex
03
Mar 20

El núcleo de Drupal tiene un sistema de usuarios, roles y permisos muy intuitivo con el que seguramente ya estés familiarizado, pero tiene sus limitaciones a la hora de crear permisos más específicos para los roles. 

Es bastante habitual querer que los usuarios de un rol tengan acceso a la información de los de otro rol concreto, pero no de todos los usuarios. Drupal nos permite asignar a un rol el permiso de ver los perfiles de los usuarios, pero no nos permite especificar que lo haga exclusivamente para un rol. Por ejemplo, un portal de un colegio puede tener un rol "profesor" y otro rol "alumno" que permita que los profesores vean el perfil de los alumnos para así obtener información como los números de teléfono de sus padres, pero no deberían poder ver los datos del resto del personal del centro. Para ello podemos programar un módulo sencillo.

La creación del módulo se puede realizar por cualquier método, por ejemplo mediante la consola de drupal, utilizando el comando "drupal generate:module" y con las opciones por defecto.

Lo primero que haríamos sería añadir un permiso nuevo, creando un fichero nombreDelModulo.permissions.yml. Este contendrá el nuevo permiso en este formato:

nombre del permiso:

  title: "Nombre del permiso"

  description: "Descripción del funcionamiento del permiso"

En los ficheros .yml es importante respetar el indentado para su correcto funcionamiento. Entre niveles, debe haber una diferencia de dos espacios (en este caso, antes de title y description, que forman parte del permiso.

Ahora debemos programar el uso del permiso para que el sitio actúe de forma distinta en función de si el usuario dispone de ese permiso o no. Drupal hace uso de "hooks" o enganches, funciones que permiten que nuestro código modifique el comportamiento original. Los usuarios en Drupal son entidades, y para modificar el comportamiento de las entidades, disponemos de distintos hooks, como hook_entity_view ("enganche_entidad_vista"). Además, podemos especificar el identificador del tipo de entidad para que actúe exclusivamente sobre dicho tipo. En este caso, sería hook_user_view (para que sólo actúe la ver entidades de tipo usuario).

En el fichero .module del módulo programamos el hook. Debe llamarse nombreDelModulo_user_view y vamos a utilizar su parámetro $entity:

function nombreDelModulo_user_view(\Drupal\Core\Entity\EntityInterface $entity){ }

En la página de la API de Drupal sobre los hook_entity_view podemos ver los parámetros que reciben, aunque si en nuestro IDE tenemos configurada una instalación de Drupal, probablemente te autocomplete el esqueleto de la función. La entidad $entity contendrá la entidad completa del usuario que queremos ver. hook_user_view actuará cuando intentemos ver el perfil de un usuario (acceder a su vista). Dentro programaremos la funcionalidad que queremos añadir, en este caso la comprobación de roles.

En la página de la API de Drupal sobre la entidad User podemos ver métodos para obtener sus roles. Utilizaremos la función "hasRole", que nos devolverá un booleano si el usuario tiene el rol deseado:

$entity->hasRole('nombre_del_rol');

El rol del usuario identificado lo podemos obtener con la función del núcleo currentUser (sin inyectar, \Drupal::currentUser()). Comprobaremos si el usuario tiene asignado el permiso que hemos creado:

$currentUser->hasPermission('nombre del permiso');

El "Access" del núcleo de Drupal se encarga de controlar los accesos. De él podemos hacer uso de la clase AccessResult para modificar las condiciones para tener o no acceso a algo. Más concretamente, AccessResultAllowed:allowedIf ("permitido si"):

\Drupal\Core\Access\AccessResultAllowed::allowedIf($booleano)

Si el módulo se llama "acceso", el permiso "ver alumnos" y el rol de los alumnos es "alumno", el hook completo sería así:

function acceso_user_access(\Drupal\Core\Entity\EntityInterface $entity) {

  $currentUser = \Drupal::currentUser();

  $allowed =
    $entity->hasRole('alumno')
    &&
    $currentUser->hasPermission('ver alumnos');

  return \Drupal\Core\Access\AccessResultAllowed::allowedIf($allowed);

}

Una vez habilitado el módulo, en la interfaz de gestión de permisos aparecerá el permiso "Ver alumnos" y los roles de usuario a los que se lo asignemos podrán ver sus perfiles. Se lo asignamos a los profesores y así sólo ellos y el administrador del sitio podrán verlos.