Access, Excel, VBA y más

Gestión de Usuarios avanzada

Retomamos el tema donde lo dejamos en el post anterior, vamos a ampliar nuestra gestión de usuarios añadiendo un nivel mas de seguridad. El método que propongo es el siguiente: Vamos a controlar a que formularios pueden entrar nuestros usuarios y a cuales no.

Para ello seguiremos los siguiente pasos:

  1. Añadiremos una nueva tabla «tblUsuariosPermisos».
  2. La relacionaremos con la tabla «tblUsuarios».
  3. Crearemos una tabla «tblUsuarioActivo».
  4. Crearemos un formulario para gestionar los permisos.
  5. Crearemos un código para guardar el usuario activo una vez entremos en la aplicación.
  6. Crearemos un módulo que al pasarle el nombre de un formulario si no tiene permiso, lo cierre directamente.
  7. Creamos un par de formularios de prueba y los probamos.

Dicho esto, vamos a ponernos manos a la obra.

Paso 1

Vamos a crear una tabla «tblUsuariosPermisos» que nos servirá para indicar, por cada uno de los usuarios de la tabla «tblUsuarios» a que formularios tiene acceso y a cuales no.

Dicha tabla ha de llevar los siguientes campos:

Nombre                                      Tipo       
IdPermiso                                  Autonumérico y clave principal
IdUsuario                                  Texto (Mismo tamaño que el IdUsuario de la tabla tblsUsuarios)
NombreFormulario                     Texto
Acceso                                     Si/No

Paso 2

Relacionamos dicha tabla con la tabla «tblUsuarios», ya he comentado en alguna ocasión la importancia de las relaciones, en nuestro caso debemos hacerlas porque sin ellas, podríamos borrar un Usuario de la tabla «tblsUsuarios» y dejar sus registros relacionados de la tabla «tblUsuariosPermisos» en el aire, ocupando un espacio absurdo.

Como veis he Marcado las tres casillas «Exigir integridad referencial» para que no me deje dar de alta un permiso de un usuario que no exista, «Actualizar en cascada….» para que si cambio el DNI de un Usuario me lo actualice en las dos tablas el solo y «Eliminar en cascada…..» para que si elimino un usuario automáticamente me elimine también los registros relacionados en la tabla «tblUsuariosPermisos» y no se nos queden registros huérfanos por ahí.

Paso 3

¿Para que necesitamos una tabla como la de «tblUsuarioActivo», bien vamos a intentar explicarlo, cuando vallamos a abrir un formulario y le pidamos a nuestro programa que compruebe si el usuario que inició la aplicación puede abrir dicho formulario, en algún sitio tenemos que indicarle a Access quien fue el usuario que inició la aplicación, esto como otras muchas cosas se puede hacer de mil maneras distintas, cada programador es un mundo, una de ellas es, una vez que hemos validado al usuario y lo hemos dejado entrar, guardar su «Id» en dicha tabla y así lo tenemos disponible cada vez que queramos saber quien es.

Nuestra tabla solo necesita un campo «IdUsuario» tipo «Texto» con el mismo tamaño que el «IdUsuario» de la tabla «tblUsuarios» y de momento solo contendrá un registro que grabaremos y leeremos mediante código cada vez que nos haga falta.

Paso 4

Lo ideal es tener un formulario para gestionar cómodamente los permisos así que aquí va una propuesta, formulario de la tabla «tblUsuarios» con un subformulario de la tabla «tblUsuariosPermisos» relacionados por el campo «IdUsuario» que hace el asistente automáticamente.:

No me critiquéis el diseño que no me he esmerado nada en él, lo he dejado tal cual me lo ha sacado el asistente que para ilustrar nuestro ejemplo sobra. Vosotros que tendréis mas tiempo ya le vais dando un toque mas bonito.

Como podéis ver al usuario «EL PEQUEÑO SALTAMONTES» solo puede entrar al formulario «frmAlmacen» que es al único donde le he marcado la casilla.

Paso 5

En nuestro formulario de acceso, donde validamos usuario y contraseña, vamos a ampliar el código para que, una vez lo valide y nos deje entrar en la aplicación, guardemos dicho usuario en nuestra tabla «tblUsuarioActivo»

El código que pongo aquí es el mismo de la entrega anterior, incluyendo las nuevas modificaciones.

Private Sub cmdAceptar_Click()

' Buscamos el dni en la tabla tblUsuarios, en caso de no
' encontrarlo avisaremos con un mensaje y saldremos del
' procedimiento.

If IsNull(DLookup("IdUsuario","tblUsuarios","IdUsuario = '" & Me.txtIdUsuario & "'" )) Then
Call MsgBox("El usuario no existe en nuestra base de datos.", vbCritical, "Atención")
Exit Sub
End If

' Si llegamos hasta aquí es porque el dni existe
' en la base de datos, por lo tanto vamos a
' comprobar si la contraseña coincide con la del
' dni introducido.

' Primero creamos una variable para
' guardar la contraseña del usuario
' que previamente hemos validado.

Dim sContraseña As String
sContraseña = DLookup("Contraseña", "tblUsuarios", _
& "IdUsuario = '" & Me.txtIdUsuario & "'")

' Una vez tenemos la contraseña en la variable "sContraseña"
' la contrastamos con la que ha introducido el usuario
' en el formulario de validación.

If sContraseña = Me.txtContraseña Then
' Informamos al usuario de que la contraseña
' es correcta y cerramos el formulario
' dándole paso al resto de la aplicación

' Además, como somos un programador que mimamos
' los detalles le daermos el mensaje personalizado
' con su nombre al usuario, para ello, buscamos primero
' en la tabla, el nombre que corresponde con el dni
' introducido.

Dim sNombre As String
sNombre = DLookup("Nombre" , "tblUsuarios" , "idUsuario= '" & _
  Me.txtIdUsuario & "'")

' Con el nombre del usuario en la variable "sNombre"
' procedemos a mostrar el mensaje personalizado.

Call MsgBox("Bienvenido " & sNombre & ", puede acceder al sistema." _
, vbInformation, "Datos correctos")

' Antes de cerrar el formulario vamos a guardar el idUsuario
' en la tabla "tblUsuarioActivo"
Dim sSQL As String
' Creamos una sentencia SQL que es una consulta de
' actualización de la tabla

sSQL = "UPDATE tblUsuarioActivo SET "  _
 "tblUsuarioActivo.IdUsuario = '" & Me.txtIdUsuario & "'"

' Al ejecutar la siguiente línea, al ser una consulta
' de actualización, Access mandará unos mensajes
' muy impertinentes sobre si quieres hacerlo o no
' pero al usuario de la aplicación no tiene que tomar
' esa decisión así que primero desactivamos los mensajes
' del sistema y a continuación ejecutamos la consulta

DoCmd.SetWarnings False
DoCmd.RunSQL sSQL
' Una vez ejecutada volvemos a activar los mensajes del sistema
DoCmd.SetWarnings True

DoCmd.Close
Else

' Si es incorrecta, informamos al usuario y llevamos
' el cursos de nuevo al cuadro de texto de la contraseña
' para que el usuario vuelva a escribirla.
Call MsgBox("La contraseña es incorrecta. Vuelva a intentarlo.", _
vbExclamation, "Datos correctos")
Me.txtContraseña.SetFocus
End If
End Sub

Un inciso, como la sentencia que hemos usado para guardar el usuario en la tabla «UPDATE tblUsuarioActivo SET ……» realmente es una consulta de actualización, para que funcione correctamente, nuestra tabla «tblUsuarioActivo» debe tener por lo menos un registro, que es el que utiliza la consulta para modificarlo por el usuario de nuestro formulario. Para ello podéis entrar en la tabla y añadir a mano el primer registro con el DNI que os de la gana.

Ahora podéis comprobar como al entrar a nuestro programa se guarda en la tabla el usuario con el que hemos entrado.

Paso 6

Ahora tenemos un usuario al que le hemos asignado una serie de permisos (nombres de formularios y si puede o no entrar a ellos) y lo que vamos a hacer es que al abrir un formulario, este compruebe antes de abrirse, si el usuario tiene permisos para ello, en caso afirmativo el formulario se abrirá y en caso negativo el formulario se cerrará avisando al usuario de que es un «Pringado» y no puede acceder.

Como el código que escribiremos para ello lo vamos a tener que repetir en todos los formularios que tengamos en nuestro programa, los actuales y los que vallamos añadiendo según crezca nuestra aplicación, no sería correcto REPETIR una y otra vez el mismo código en cada uno de ellos, ¿Y por que os digo eso? pues muy sencillo, vamos a suponer que con el tiempo y gracias a nuevos conocimientos, podemos mejorar el código que hemos escrito añadiéndole nuevas funciones, una vez tengamos la mejora tendríamos que ir uno por uno en todos los formularios donde lo hemos usado y actualizar el nuevo código, obviamente esto es un engorro.

¿Que os propongo? pues escribirlo solo una vez, crearemos un módulo independiente, que no esté asociado a ningún formulario, y escribiremos el código ahí, luego solo tendremos que llamarlo desde cada formulario que lo necesitemos y el día que tengamos que mejorarlo solo lo haremos una vez.

Pues ala, manos a la obra, pestaña «Crear», os recuerdo que estoy en Access 2010, al final encontramos el grupo «Macros y Código», pulsamos sobre «Módulo»

Ahora vamos a escribir un procedimiento que al llamarlo, si no tiene permiso, cerraremos el formulario antes siquiera de abrirlo, para ello, al llamarlo le pasaremos el nombre del formulario.

Public Sub Permiso(sNombreFormulario As String)

' Lo primero que haremos es cargar el usuario activo
Dim sUsuarioActivo As String
sUsuarioActivo = DLookup("IdUsuario", "tblUsuarioActivo")

' A continuación buscaremos de la tabla "tblUsuariosPermisos"
' que dice el campo "acceso" de ese formulario del usuario
' activo. Para ello usamos el Dlookup añadiendo los
' filtros por IdUsuario y Nombre del Formulario

Dim bPermisoFor As Boolean
bPermisoFor = DLookup("Acceso", "tblUsuariosPermisos", "IdUsuario= '" _
& sUsuarioActivo & "' AND NombreFormulario= '" _
& sNombreFormulario & "'")
' Con un Si o un No, en la variable "bPermisoFor"
' tomamos una decisión.
If bPermisoFor = False Then 'Informamos al usuario y le cerramos el formulario.
Call MsgBox("Usted no tiene permisos para visualizar este formulario" _
," Contacte con el administrador", vbCritical, Atención)
DoCmd.Close acForm, sNombreFormulario
End If

' Logicamente si la variable es SI no hacemos nada y
' dejamos que el formulario siga abriéndose.
End Sub

Paso 7

El que haya llegado hasta aquí es un campeón porque mira que se me ha hecho extenso 🙂 . ¿Queréis verlo funcionar, verdad? pues vamos a dar el último paso. Vamos a crearnos un par de formularios. Para hacer mis pruebas han sido dos formularios en blanco, ya habrá lugar de asignarle origen de datos y meterles sus campos y demás, para el caso que nos ocupa, están vacíos. Les he llamado «frmAlmacen» y «frmVentas» tal y como queda reflejado en el paso 4 del tutorial.

Las siguientes líneas de código las he colocado en el evento «Al abrir» del formulario, comento esto porque también tenéis otro evento en los formularios que se llama «Al Cargar», la diferencia entre ellos es que «Al abrir» se produce antes de que se muestre el formulario en pantalla y el evento «Al cargar» cuando ya se muestra el formulario en pantalla con todos sus controles. Como veis, poniéndolo en el evento «Al abrir» tomamos la decisión antes de que se muestre en pantalla.

Private Sub Form_Open(Cancel As Integer)
'Llamos al procedimiento de nuestro módulo
'pasándole el nombre del formulario
Call Permiso(Me.Name)
End Sub

Funcionamiento

Al abrir el formulario llamamos al procedimiento «Permiso» que tenemos en el módulo, pasándole como parámetro el nombre de nuestro formulario, una vez pasado el testigo al procedimiento este cargará el usuario activo y comprobará si el permiso que le hemos puesto a ese usuario concreto y con ese nombre de formulario le permite abrir dicho formulario, en caso negativo, nuestro procedimiento cierra directamente el formulario avisando al usuario de que no puede abrirlo y que se busque un enchufe con el administrador para que le deje hacerlo.

Consideraciones finales

He resumido mucho el código para que sea fácil de entender pero me he dejado algunas cosas en el tintero, tampoco os lo voy a dar todo hecho ¿no? 🙂 algunas de las mejoras que debéis incorporar por ejemplo es el control de errores en todos los procedimientos, ¿Que pasa si se os ha olvidado asignar los permisos de un usuario concreto? pues que vuestro procedimiento no encontrará el nombre del formulario en la tabla «tblUsuariosPermisos» y os devolverá un bonito error. ¿Que pasa, por ejemplo, si os equivocáis al escribir el nombre del formulario cuando estáis asignando los permisos? pues al igual que antes que no lo encontrará y devolverá otro error, por lo que deberíais de implementar algún método para que la selección de los formularios en la asignación de permisos sea automática y no podáis cometer errores al escribirlo, ¿Que pasaría si……….? Pues eso, que podría tirarme horas y horas sacándole pegas y mejorando muchiiiiiiiiiiiiisimo la aplicación.

Eso precisamente, es lo que hace tan entretenido, provechoso y didáctico la labor de un programador y de la cual yo disfruto mucho.

Si estás interesado en aprender mas puedes solicitar información sobre nuestros cursos de programación orientada a objetos con Visual Basic para Access.

Salir de la versión móvil