Blog


CONTROL DE ACCESO A CONTENIDOS EN DRUPAL 7 CON RULES

24 / 06 / 2013 Drupal

Cuando se trata de restringir el acceso a los contenidos a los usuarios en Drupal podemos optar por bastantes módulos disponibles (Content Access, Protected Node, Taxonomy access control, Nodeaccess, etc.).

Estos módulos nos ayudan a restringir el acceso a determinados usuarios o roles basados en el tipo de contenido, taxonomías..., pero si lo que necesitamos es restringir el acceso a determinados usuarios que cumplan determinadas características de forma más personalizada, el uso de estos módulos no nos sirve, por lo que necesitamos algo más específico. Me refiero por "forma personalizada" a por ejemplo, permitir el acceso a un usuario cuyo campo o propiedad coincida con un valor determinado, y que éste, puede cambiar, y que esté relacionado de alguna manera, con otra propiedad, de un nodo por ejemplo.

Con restringir el acceso no me refiero, obviamente, a no mostrar en bloques, vistas o menús los contenidos que no pertenezcan a un determinado rol o usuario, sino a que no pueda accederse mediante la URL a un nodo, o a un fichero privado.

Para que quede claro, vamos a hacer esto con un ejemplo.

Vamos a montar un CMS muy sencillo para organizar determinadas tareas por grupos de trabajo. Los usuarios pertenecerán a un determinado grupo de trabajo. Las tareas podrán tener archivos adjuntos, e irán asociadas a un determinado grupo de trabajo. Habrá un rol para determinados usuarios que sea "supervisor", que podrán acceder a cualquier tarea y grupo de trabajo.

Antes de nada, lo primero que haremos será configurar drupal para que el acceso a los ficheros en el servidor sean de acceso privado, esto es, no los servirá directamente el servidor web, sino que será drupal el que se encargue de servir estos ficheros si se tienen los credenciales adecuados, y por lo tanto, no estarán disponibles públicamente.

Para ello, nos iremos a Administración->Configuración->Sistema de archivos, y pondremos una ruta en Ruta al sistema de archivos privado, por ejemplo: "sites/default/files/private", guardamos la configuración, y nos mostrará ahora una opción más en la sección de Método predeterminado de descarga:



Hecho esto, los ficheros ya no serán servidos directamente por el servidor web (Apache, IIS, etc.) sino que será Drupal el que los sirva.

Lo que haremos ahora será crear el tipo de contenido Grupo de trabajo, para el ejemplo usaremos tipos de contenido muy simples, en este caso, sólo pondremos un texto, un título, un documento adjunto, y las referencias a los usuarios, utilizando para ello el módulo Entity Reference. Necesitaremos instalar también Entity API, Chaos tools suite y Node Access rules

En el ejemplo he usado la siguiente configuración para los campos básicos, la referencia a los usuarios lo explico a continuación.



Añadiremos después un nuevo campo de tipo "Entity Reference" (nos tiene que aparecer si hemos añadido los tres modulos citados anteriormente), y en control he elegido "Casillas de seleción/botones de opciones"

Una vez dado en guardar, aparecerá la siguiente pantalla:



En Tipo destino elegiremos "Usuario", las demás opciones podemos dejarlas como están. Damos a Guardar opciones de campo y en la pantalla siguiente en Número de valores ponemos por ejemplo el valor "Ilimitado" y guardamos.

Ahora crearemos el rol supervisor, y crearemos 4 usuarios, usuario1, usuario2, usuario3, usuario4, y otro usuario más con el rol supervisor, que en mi caso lo he llamado también supervisor.
Ahora crearemos dos grupos de trabajo, "grupo de trabajo 1" y "grupo de trabajo 2" por ejemplo, y asignaremos los usuarios usuario1 y usuario2 al primero, y usuario3 y usuario 4 al segundo. A la hora de crear un grupo de trabajo podremos elegir de la lista los usuarios existentes gracias al campo de tipo Entity Reference que asignamos al campo "usuario" del tipo de contenido "Grupo de trabajo" Podemos verlo en la siguiente imagen:



Para el tipo de contenido Tarea haremos lo mismo, con un campo de tipo fichero y otro campo de tipo "Entity Reference" que hará referencia a un tipo Nodo, y y en el tipo de entidad seleccionaremos "Grupo de trabajo", pero esta vez en Número de valores seleccionaremos 1, pues una tarea sólo la vamos a asociar a un solo grupo de trabajo.
Ahora sólo tenemos que añadir tareas y seleccionar de la lista de grupos a qué grupo va a estar asignada.

Ahora ya tenemos el siguiente esquema, tenemos varios grupos de trabajo, con determinados usuarios y varias tareas por hacer. Los usuarios sólo podrán acceder a la información de su grupo y sus tareas.
Tal y como está ahora, cualquier usuario podrá acceder mediante la URL a cualquier nodo, nosotros lo que vamos a hacer es controlar este acceso. Por ejemplo, "usuario 1" no pertenece al "grupo 2", sin embargo, si accede mediante esta URL "http://vabadus.demos/content/grupo-de-trabajo-2" nada le impide acceder al nodo, de la misma forma que tampoco tiene impedimento de acceder a la tarea "Tarea 3 gr 2", que es una tarea del "grupo 2", y por lo tanto tampoco debería poder tener acceso.

Vamos a crear para ello dos Rules donde configuraremos este control de acceso al contenido. Una vez instalado el módulo Rules, en configuración tendremos una sección llamada "Flujo de trabajo" y dentro de ella "Rules"



Si hacemos click sobre Rules, tendremos varias pestañas, por defecto estaremos en Reglas, ahí podremos empezar a crear las nuevas reglas que Drupal usará.



Para simplificar vamos a crear dos tipos de reglas, una para limitar el acceso a las tareas o grupos a los usuarios que no pertenezcan al grupo correspondiente, y otra para limitar el acceso a todos los usuarios no registrados. Aunque esto se puede hacer en una sola regla, o en más reglas, cada uno elige la forma en la que desea trabajar. Primero vamos a crear la regla para evitar el acceso a un grupo o tarea a un usuario que no corresponda.

Las reglas se disparan con un evento, para acceder a un nodo, Drupal lanza el evento Request for view rights, por lo tanto, al crear la regla, le daremos un nombre, unas etiquetas si quisiéramos localizarla más facilmente al hacer búsqueda, y el evento al que reaccionará esta regla será la mencionada anteriormente: Request for view rights



Ahora tendremos que añadir una condición y una acción, la acción está clara, será denegar el acceso, por lo tanto, vamos a añadir la acción a la regla, entre todas las que tiene Drupal, la que queremos utilizar es la de la sección Node Access llamada "Do not allow editing/viewing/creating/deleting of Node". Creo que esto está claro, si se cumple la condición que crearemos a continuación cuando drupal solicite permiso de acceso a un nodo, lo denegaremos.
Ahora vamos a crear la condición o condiciones. Le daremos a añadir una condicion, y elegiremos en la primera lista de opciones que nos aparece dentro de la sección Nodo la siguiente opción: El contenido es de tipo Una vez seleccionado esto, en "Data selector" ponemos "node", y en "tipos de contenido" tendremos los tipos de contenido que hemos creado en nuestro sitio, en este caso seleccionaremos Grupos de trabajo.



Ahora toca añadir las otras dos condiciones, lo que queremos comprobar es que el usuario actual no esté en la propiedad "field_usuario" del nodo, o el nombre que diéramos al campo de tipo "entity reference" del tipo de contenido "Grupo de trabajo" para referenciar a los usuarios, en mi caso, el nombre es "field_usuario". Para ello, al crear la nueva regla (si no elegimos nada es una regla de tipo AND, es decir, si se cumplen todas las reglas que vamos a poner se deniega el acceso) vamos a elegir "Data comparison", vamos a comprar datos del nodo, no propiedades o taxonomías, ya que estos datos podrán cambiar dinámicamente. Una vez elegido el data comparison tendremos que crear la igualdad, en este caso lo que haremos es crear la igualdad y luego negarla entera. En Data to Compare introduciremos lo siguiente: site:current-user, en el operador elegimos es uno de ya que el campo field_usuario era de tipo múltiple, (en un grupo podía haber varios usuarios), y en "Data Value" ponemos node:field-usuario, y por ultimo, recordar negar la condición más abajo. Es decir, si el nodo es de tipo Grupo de trabajo y el usuario NO es uno de los que tiene el grupo de trabajo en el campo field-usuario NO damos acceso al nodo.
Sólo nos queda una cosa, dijimos que los supervisores tendrían acceso a todas las tareas o grupos, por lo tanto nos queda añadir otra condición, que el usuario actual no tenga el rol "Supervisor". Para ello añadimos una condición más a las dos anteriores. En este caso no es Data comparison, porque no son datos de un nodo en concreto, para ello tenemos en la sección Usuario de la lista e condiciones el tipo "El usuario tiene rol(es)", después negaremos la condición. Una vez pulsada la opción de la lista, rellenamos el Data selector con site:current-user ya que es el usuario conectado el que queremos controlar, y abajo, en los roles, seleccionar "Supervisor", sin olvidarnos de negar la condición. Así pues la regla queda de la siguiente manera:



Explicamos la captura.
La regla "Acceso a grupo de trabajo" se dispara con el evento "Request for view rights", si las condiciones se cumplen la acción es NO permitir la edición, vista, creación o borrado del nodo.
La condiciones son: El nodo es de tipo "Grupo de trabajo", el usuario actual NO es uno de los que están en el campo field_usuario del nodo y el usuario NO tiene el rol supervisor.

Si probamos ahora a entrar al sitio con el "Usuario 1" que está en el grupo uno, podemos ver que puede acceder a la siguiente URL: http://vabadus.demos/content/grupo-de-trabajo-1, pero que le sale acceso denegado si intenta acceder a la URL: http://vabadus.demos/content/grupo-de-trabajo-2, como se puede ver en la imagen siguiente:



Ahora vamos a ver cómo podemos hacer esto para las tareas, esto no es trivial, puesto que las tareas no hacen referencia directa a los usuarios como sí hacían los grupos en el campo field_usuario, las tareas se relacionan solo con los grupos, y son estos, los que hacen referencia a los usuarios, para ello, hay que utilizar un pequeño truco, que a priori no es intuitivo.
La regla la generamos igual que para los grupos, el evento es "Request for view rights", la acción es denegar la vista, edición, creación y acceso, y en las condiciones, la primera es igual, por tipo de nodo, en este caso "Tarea". Y es ahora cuando viene el pequeño truco, la condición sería que el usuario actual esté en el grupo al que hace referencia la tarea. Bien, la tarea hace referencia al grupo mediante un campo de tipo "Entity Reference" llamado field_grupo_de_trabajo, al menos en mi caso, y el grupo de trabajo hace referencia a los usuarios mediante el campo field_usuario también de entity reference.
El problema es que en las Reglas no se puede acceder a campos de una entidad referenciada directamente, para ello, antes de añadir las condiciones que harán referencia a los campos de un tipo de contenido referenciado desde este tipo de nodo tendremos que añadir una condición previamente. La condición será de tipo La entidad tiene el campo, el data selector será el campo de tipo Entity Reference que referencia a la clase intermedia (Grupo de trabajo) "node:field-grupo-de-trabajo", y el campo que seleccionaremos más abajo de la entidad "Grupo de Trabajo" será field_usuario, que es de donde sacaremos los datos para comparar con el usuario conectado al sitio. En la siguiente imagen vemos cómo quedaría la regla:



Y ahora ya sí, en la siguiente regla del tipo data comparison sí podemos comparar el usuario actual (site:current-user) mediante el operador "es uno de" con el campo field_usuario de la entidad referenciada del field_grupo_de_trabajo del tipo de nodo Tarea Recordad negar la condición, y que no se os olvide añadir la condición de que el usuario no tenga el rol Supervisor. En las dos imagenes siguientes vemos cómo quedaría la condición y la regla al completo.





Ahora podremos comprobar que el "Usuario 1" puede acceder a la tarea 2 del grupo 1, cuya URL es http://vabadus.demos/content/tarea-2-gr-1, pero no puede acceder a la tarea 3 del grupo 2 cuya URL es http://vabadus.demos/content/tarea-3-gr-2, puesto que el "Usuario 1" no pertenece al grupo 2, a quien corresponde la tarea 3.

Esto es todo, espero que les haya sido de utilidad.



ARTÍCULOS RELACIONADOS