Restringir los datos según los privilegios o la información guardada en la memoria de sesión

En el desarrollo de aplicaciones modernas, la seguridad y la gestión fina del acceso a los datos son esenciales. Gracias al evento restrict de 4D, es posible filtrar dinámicamente los datos accesibles a un usuario en función de su perfil, privilegios e información almacenada en la sesión.

Este blog explica cómo aprovechar este evento, particularmente en el contexto de una integración con 4D Qodly Pro, para asegurar que sólo los datos relevantes sean expuestos.

Aplicación de demostración de revisión de rendimiento

Entendiendo el evento restrict

El evento restrict es un mecanismo de filtrado automático aplicado a las entidades de una clase de datos en ORDA. Es disparado para restringir los resultados de las búsquedas (all(), query(), API REST access, etc.) basado en un contexto específico (información de usuario, privilegios, etc.).

Principales ventajas:

  • Filtrado dinámico: cada vez que se ejecuta una consulta, se aplica automáticamente el filtro definido por restrict.
  • Control de acceso granular: el acceso puede restringirse totalmente o limitarse a registros específicos en función de los roles de usuario, privilegios o datos contextuales como la ubicación geográfica o el departamento.
  • Separación de la lógica: la implementación de este filtrado es independiente de la lógica comercial de la aplicación, lo que facilita el mantenimiento y las actualizaciones de seguridad.

Para más detalles, la documentación oficial de 4D sobre el filtrado de entidades ofrece una visión completa de esta funcionalidad.

Privilegio vs. Restricción: PRINCIPALES Diferencias

En 4D, el control de acceso se gestiona a través de privilegios y de restricciones, que funcionan juntos para garantizar un acceso seguro y granular a los datos. Entender la distinción entre estos dos mecanismos es esencial para diseñar un modelo de seguridad robusto.

Privilegios: Control del acceso a las estructuras de datos

Un privilegio determina si un usuario está autorizado a acceder a una tabla, un campo o una función de la base de datos. Actúa como un mecanismo de control de acceso de alto nivel que concede o niega el acceso a todo un conjunto de datos o a una funcionalidad.

Ejemplo de casos de uso:

  • Un usuario de base puede tener acceso de sólo lectura a la tabla Empleados, pero no puede editar ni eliminar registros.
  • Un gerente puede tener privilegios adicionales que le permitan modificar los registros de empleados dentro de su departamento.
  • Un administrador de RRHH puede tener acceso a campos sensibles como la información salarial, mientras que los empleados estándar no pueden ver esos detalles.

Restricciones: Refinar el acceso a nivel de registro

Mientras que los privilegios controlan el acceso a nivel estructural, las restricciones determinan los registros específicos dentro de una tabla autorizada que un usuario puede ver o con los que puede interactuar. El evento on restrict filtra dinámicamente los datos basándose en el contexto del usuario, asegurando que los usuarios sólo acceden a los registros relevantes respetando las reglas de seguridad predefinidas.

Ejemplo de uso:

  • Un colaborador sólo puede acceder a sus propios registros en la tabla Empleados.
  • Un directivo puede ver los registros de sus subordinados directos.
  • Un administrador de RRHH puede ver todos los empleados.

Casos de uso

Ejemplo 1: Combinación de privilegios y contexto de sesión para restringir los datos

En este ejemplo, implementamos el evento restrict en la clase de datos Employee para filtrar la lista de empleados devuelta. El siguiente código ilustra cómo utilizar la información de sesión y los privilegios para determinar el acceso a los datos:

Function event restrict() : cs.EmployeeSelection
var $obj : Object
If (Session=Null)
  $obj:=Storage
Else
  $obj:=Session.storage
End if
Case of
  : (Session.hasPrivilege("authentify"))
   return This.all()
  : (Session.hasPrivilege("generatePDF"))
   return This.all()
  : (Session.hasPrivilege("createReview"))
   return This.all()
  : (Session.hasPrivilege("webadmin"))
   return This.all()
  : ($obj.Employee.role="Collaborator")
   return This.query("ID = :1"; $obj.Employee.ID)
  : ($obj.Employee.role="Manager")
   return This.query("ID_Supervisor = :1"; $obj.Employee.ID)
  : (($obj.Employee.role="HR") && (Session.hasPrivilege("hr")))
   return This.all()
  Else
   return This.newSelection()
End case

Cómo funciona

  • Filtrado basado en privilegios: la función hasPrivilege() verifica si la sesión del usuario incluye privilegios específicos. Por ejemplo, los empleados de RRHH con el privilegio «hr» tienen acceso a todos los registros de empleados.
  • Elevación temporal de roles: para acciones como la autenticación, la generación de documentos o la creación de revisiones, la promoción de privilegios puede conceder temporalmente derechos ampliados sin alterar la configuración global del usuario.
  • Filtrado basado en la sesión: la propiedad de rol (almacenada en el almacenamiento o la sesión) dicta los niveles de acceso. Los colaboradores sólo pueden ver sus propios registros, los gerentes pueden acceder a los empleados subordinados y el personal de RR.HH. puede ver a todos los empleados.
  • Retorno seguro por defecto: si no se cumple ninguna condición, This.newSelection() garantiza que el usuario no reciba ningún dato en lugar de un acceso sin restricciones.

Nota: el privilegio webadmin es utilizado por el Explorador de Datos en 4D. Si desea que sus datos sean accesibles a través del Explorador de Datos, debe manejar el caso del privilegio webadmin. En nuestro ejemplo, concedemos acceso completo al Explorador de Datos devolviendo This.all() cuando este privilegio está presente.

Ejemplo 2: Integración en Qodly Studio mediante acciones o funciones estándar

Este segundo ejemplo muestra cómo restringir el acceso a las revisiones en la clase de datos Review en función del rol del usuario.

Function event restrict() : cs.ReviewSelection
var $obj : Object
If (Session=Null)
  $obj:=Storage
Else
  $obj:=Session.storage
End if
If ($obj.Employee.role=Null)
  return Null
End if

Case of
  : (($obj.Employee.role="HR") && (Session.hasPrivilege("hr")))
   return This.all().orderBy("Date desc")

  : ($obj.Employee.role="Manager")
   return This.query("Employee.ID_Supervisor = :1"; $obj.Employee.ID).orderBy("Date desc")

  : ($obj.Employee.role="Collaborator")
   return This.query("ID_Employee = :1"; $obj.Employee.ID).orderBy("Date desc")

  : (Session.hasPrivilege("webadmin"))
   return This.all()

Else
  return This.newSelection()
End case

Utilización de acciones estándar

En la página colaborador de la aplicación Qodly, el usuario tiene el rol de colaborador, y sólo puede consultar sus propias reseñas.

En Qodly Studio, definimos la acción estándar All para llenar la tabla de datos en el evento on load de la página colaborador. Normalmente, la acción estándar All recupera todas las opiniones. Pero, como hemos añadido el evento restrict a la clase de datos Review. Sólo recuperamos las reseñas autorizadas por el colaborador.

Uso de funciones personalizadas

En la página Manager, los usuarios con el rol «Manager» pueden ver todas las revisiones relacionadas con sus subordinados. Añadimos una función de filtrado avanzado para refinar los resultados por año y estado.

En la clase de datos Review, tenemos la función loadReviews:

exposed Function loadReviews($departement : cs.DepartementEntity; $year : Integer; $status : cs.ReviewStatusEntity) : cs.ReviewSelection
Case of
  : (($departement=Null) && ($status=Null))
   return This.query("Date >= :1 AND Date <= :2"; String($year)+"/01/01"; String($year)+"/12/31")

  : (($departement#Null) && ($status=Null))
   return This.query("Employee.ID_Departement = :1 AND Date >= :2 AND Date <= :3"; $departement.ID; String($year)+"/01/01"; String($year)+"/12/31")

  : (($departement=Null) && ($status#Null))
   return This.query("ID_Status = :1 AND Date >= :2 AND Date <= :3"; $status.ID; String($year)+"/01/01"; String($year)+"/12/31")

  : (($departement#Null) && ($status#Null))
   return This.query("Employee.ID_Departement = :1 AND ID_Status = :2 AND Date >= :3 AND Date <= :4"; $departement.ID; $status.ID; String($year)+"/01/01"; String($year)+"/12/31")

Else
  return This.newSelection()
End case

En Qodly Studio, esta función se activa mediante el evento «on data change» para las fuentes de datos «year» y «status».

Para la entrada year:

blank

Para el cuadro de selección status:

blank

El filtro personalizado se combina con la restricción global proporcionada por on restrict, lo que le permite refinar sus resultados respetando las reglas de seguridad definidas de antemano.

Siguiente

El evento restrict de 4D demuestra ser una poderosa herramienta para gestionar dinámicamente el acceso a los datos. Al aprovechar los privilegios de usuario y el almacenamiento de sesiones, garantiza un control de acceso granular sin añadir complejidad a la lógica de negocio. Además, la integración con mecanismos complementarios como la promoción y la adición de filtros personalizados ofrecen una mayor flexibilidad para satisfacer requisitos específicos.

Para profundizar en este tema, consulte la documentación oficial sobre las entidades ORDA, así como el blog 4D dedicado al filtrado de datos.

Vanessa Talbot
• Propietario de producto - Vanessa Talbot llegó al equipo de 4D Program en junio de 2014. Como Propietario de producto, está a cargo de escribir las historias de los usuarios y luego traducirlas a especificaciones funcionales. Su papel es también asegurarse de que la implementación de la funcionalidad entregada cumpla con las necesidades del cliente. Desde su llegada, ha trabajado en la definición de funcionalidades claves en 4D. Ha trabajado en la mayoría de las nuevas funcionalidades de multi hilo apropiativo y también en un tema muy complejo: la nueva arquitectura para la aplicación engined. Vanessa es licenciada por Telecom Saint-Etienne. Comenzó su carrera en el Instituto de Investigación Criminal como desarrolladora del departamento audiovisual. También ha trabajado en medios de comunicación y en el ámbito médico como experta en soporte técnico, producción y documentación de nuevas funcionalidades.