Muchas veces, por
desconocer las metodologías de programación, o, más sencillamente, por ignorar
el potencial de los lenguajes de programación, nos vemos acorralados frente
a problemas que en muchos casos tienen una solución verdaderamente fácil.

La mayoría nos habremos
preguntado alguna vez: para qué tanta matemática en las carreras informáticas.
Más de uno se habrá preguntado para qué puede servirnos la matemática discreta,
por ejemplo. Y, aunque algunas veces nos disgusta estudiarla, hay que reconocer
que su lógica ayuda a resolver muchisimos aspectos de la programación. En el
presente artículo veremos por qué es así.

Recientemente, me
vi en la tarea de realizar la intranet de una organización mediana. Uno de los
requisitos (como en la mayoría de estas aplicaciones) era la creación de grupos
de usuarios con diferentes niveles de privilegios.

El problema se plantea
a la hora de planificar de qué manera podemos desarrollar un sistema eficiente
para la utilización de grupos de usuarios. Cómo podemos hacer que la aplicación
reconozca los privilegios de cada usuario dependiendo del grupo al que pertenezca.
Por qué utilizar grupos y no darle privilegios a cada usuario en particular?
En el ejemplo, más adelante, veremos por qué.

Es probable que a
simple vista parezca algo sencillo de resolver, porque nuestra lógica resuelve
este tipo de problemas rápidamente. Pero, que tan fácilmente puede hacerlo una
computadora sin nuestra intervención?

Primero, planteemos el problema.

Vamos a suponer que nuestro sistema tiene varias funciones:

  • Consulta de datos
  • Modificación de datos
  • Eliminación de datos
  • Alta/Modificación de usuarios
  • Eliminación de usuarios

Es probable que algunas
personas resuelvan este problema asignando un número de identifiación a cada
usuario en particular. Por ejemplo, algunos usuarios podrían tener un campo
en su registro con el número 1, correspondiente a los administradores, otros
con el número 2, correspondiente a los operadores, y, por último, con el número
3 los usuarios comunes o invitados. El grupo de Administradores posee todos
los privilegios, el grupo Operadores está autorizado sólo a consultar y modificar
datos, y el grupo Invitados sólo tiene permiso para consultar datos. Según el
número asignado a cada usuario podríamos decirle a la aplicación qué permisos
tiene.

El problema se torna
complejo cuando queremos quitar o añadir un permiso específico a todo un grupo
de usuarios. Por ejemplo, si quisieramos que también los operadores puedan agregar
usuarios, pero, sólo algunos operadores. Es esto sencillo? Si nos detenemos
a pensar un momento, esta situación empieza a complicarse.

Queremos que cinco de nuestros operadores estén autorizados para agregar usuarios,
entonces, le asignamos el número 4 a su registro… tendremos que modificar
la aplicación!

También queremos quitarle una función a todos los usuarios comunes… también
tendremos que modificar toda la aplicación para que reconozca el cambio!

A simple vista está claro que sería mucho más sencillo utilizar grupos con distintos
niveles de privilegios y realizar los cambios directamente sobre el grupo y
no sobre cada uno de los usuarios.

A partir de estas funciones, necesitamos
armar grupos con diferentes permisos para ejecutarlas, por ejemplo:

  • Administradores
  • Operadores
  • Invitados

A toda una serie
de usuarios le asignaremos el identificador 1, correspondiente a los administradores,
y así sucesivamente con los demás.

En este momento podríamos pensar: “Aún seguimos con el mismo problema!”. Y eso
será cierto si no le damos valores a las funciones del sistema.
Para quienes estén habituados al diseño de aplicaciones la respuesta será casi
instantánea: operaciones bit a bit.

Aunque algo complejas para aquellos que no entiendan el sistema binario, las
operaciones bit a bit son una solución eficiente para este tipo de problemas.
Veamos ahora cómo implementarlas.

Necesitamos que cada
grupo de usuario tenga ciertos privilegios sobre las funciones del sistema.
Numerando dichas funciones, podemos decir cuáles de ellas están habilitadas
a un grupo específico. Siguiendo con el ejemplo:

1 – Consulta de datos

2 – Modificación de datos

3 – Eliminación de datos

4 – Alta/Modificación de usuarios

5 – Eliminación de usuarios

Empecemos con los
administradores. Ellos tendrán todas las funciones disponibles. Cómo representar
estos permisos? Lo haremos de la siguiente manera:

El bit
más significativo es siempre el que se encuentra más a la izquierda.

Función:
5 4 3 2 1

Permiso: 1 1 1 1 1

Donde 1 equivale
a autorizado y 0 a no autorizado.

El grupo de operadores
debería tener, entonces, los siguientes valores:

Función:
5 4 3 2 1

Permiso: 0 0 1 1 1

Las últimas dos funciones
no están habilitadas para este grupo.

Por último, para
los usuarios comunes:

Función:
5 4 3 2 1

Permiso: 0 0 0 0 1

Este grupo solo puede
ejecutar la primer función: “Consultar datos”.

Lo interesante de
este modelo es la posibilidad de utilizar operaciones bit a bit para consultar
qué funciones están habilitadas para cada grupo.

En nuestro ejemplo, los administradores, tienen asignados el número binario
11111, que en decimal se representa como 31. Entonces, en el registro del grupo,
deberemos poner como privilegios el valor 31; paciencia, ya veremos por qué.

Ahora, tenemos que asignarles un valor a cada función de la aplicación para
que pueda evaluarse con los privilegios de cada grupo de usuarios.
Veamos la representación decimal de cada número binario en nuestro ejemplo:

Funcion 1: 0 0 0 0 1 = 1

Funcion 2: 0 0 0 1 0 = 2

Funcion 3: 0 0 1 0 0 = 4

Funcion 4: 0 1 0 0 0 = 8

Funcion 5: 1 0 0 0 0 = 16

Esto nos abre la
posibilidad de asignar diferentes niveles a cada grupo de la siguiente forma:

3 – Usuarios       : 0 0 0 0 1 = 1

2 – Operadores     : 0
0 1 1 1 = 7

1 – Administradores: 1 1 1 1 1 =
31

Ahora, en nuestra
aplicación queremos consultar cuáles privilegios tiene un usuario en particular.
El programa debería verificar a cuál grupo pertence el usuario que quiere ejecutar
la función y a partir de los permisos que tenga el grupo habilitar dicha función.

En pseudocódigo ésta operación sería:

valor_funcion = 4
grupo_usuario = 2
permisos_grupo = 7
si ( 4 está en 7 )
ejecuta funcion
sino
"No está autorizado para ejecutar esta función"
fin si

Para este tipo de operaciones
se utiliza el operador lógico AND. Veamos el mismo
ejemplo a nivel bits:

4
= 0 0 1 0 0 -> Valor de la función

AND

7 = 0 0 1 1 1 -> Valor del grupo de usuario

————–

    0 0 1 0 0 = 4
-> Resultado

Este resultado nos
dice que el bit comparado está puesto a 1 en el número consultado.

Veamos un ejemplo en el cual el mismo grupo no está autorizado a ejecutar la
función:

16
= 1 0 0 0 0

AND

7  = 0 0 1 1 1

————–

0 0 0 0 0 = 0

El resultado es 0,
por lo tanto, ese grupo de usuarios no está autorizado a ejecutar la función.

Volviendo al problema, ahora resulta mucho
más sencillo agregar o eliminar privilegios a un grupo: basta con modificar
el estado de un bit en el número asignado. Si ahora quisieramos que el grupo
Operadores tuviese permiso para eliminar usuarios (sólo a manera de ejemplo!)
bastaría con poner el bit correspondiente a 1. Este tipo de operación se realiza
con el operador OR:

7
=0 1 1 1

OR

16 = 1 0 0 0 0

————–

1 0 1 1 1
0 = 23

En un principio puede resultar difícil
comprender las operaciones bit a bit, pero, a medida que van surgiendo situaciones
como la planteada en este artículo, nos damos cuenta que es una solución sencilla
y, sobre todo, eficiente.

Como novato en PHP este problema también se me ha planteado y tuve que resolverlo, asi que, en
un próximo artículo, veremos cómo aplicar estas operaciones con dicho lenguaje.