PHP

Autenticación de usuarios en PHP y MySql

Este tutorial es una replica de Autenticación de usuarios en PHP y MySql . Como decía anteriormente, en algunos sistemas a veces un requerimiento es que se manejen privilegios y por lo tanto usuarios, esto con el fin de controlar lo que cada usuario puede hacer/ver una vez dentro del sistema. En esta entrada únicamente se muestra como autenticar a los usuarios para entrar al sistema, es decir, cada usuario tendrá los mismos privilegios; aunque la tabla de usuarios de MySql (que mostrare mas adelante) ya incluye un campo que determina el tipo de usuario este campo no sera utilizado por ahora. Sin mas preámbulos muestro el ejemplo…

La base de datos

Como siempre que voy a hacer uso de una BD, empezare mostrando el script para recrear las tablas que usare en el ejemplo:

La base de datos que usare se llama prueba. Como se observa únicamente son dos tablas, ademas, he creado un catalogo con los diferentes tipos de usuario que pudiera haber, solo he añadido dos tipos de usuario (Administrador y Usuario normal) a modo de ejemplo, pero se pueden añadir mas. Si observas, inserto un usuario de prueba. Si quieres asignar otro password al usuario de prueba puedes utilizar esta sencilla herramienta que te permite generar un Md5 a partir de una cadena cualquiera: obtener_md5.php

Supongo que para el momento de estar leyendo este articulo ya tienes el software necesario (ho al menos piensas instalarlo). Como he visto que los visitantes muchas veces son estudiantes de carrera ho aficionados a la programación; pero con poca experiencia (me incluyo), voy a listar las herramientas de software necesarias que debes tener yá en tu maquina si quieres probar este exquisito código :), puedes usar otro servidor y otro DBMS, pero yo use estas:

Como ves son pocos requisitos, si no tienes alguno este es el momento para que lo instales. El servidor de correo de hecho es opcional, solo lo instale para hacer pruebas en mi computadora local (una laptop), si tienes dudas sobre hMailServer en la misma pagina viene mucha documentación acerca de como instalarlo y configurarlo. Si tienes más dudas puedes preguntarle al oráculo (google) escribiendo esto ‘hmailserver y php’.

Bueno vamos a lo interesante…

El código fuente

index.php
Este archivo permite mostrar la ventana de Login, es en esta como es de suponerse el usuario introduce su nombre de usuario, su password y le da click al botón enviar, bueno muestro el código:

Como se puede ver para mostrar los mensajes de error utilizo la librería JQuery, ya que me pareció que usar un alert() de javascript es algo feito, jajajaj. Como se ve el archivo en si solamente crea un formulario en el cual se dibujan dos cajas de texto; una para el usuario y otra para el password, un link para ir a la pantalla de recuperación del password en caso de que al usuario se le haya olvidado y por ultimo se crea un botón tipo submit para enviar la información. Para validar campos vacíos también utilizo JQuery. Ademas se puede ver que envió los dos datos de las cajitas a un archivo llamado validarUsuario.php por el método POST; el cual se encargara de acceder a la BD y verificar que los datos sean correctos.

Otra cosa interesante que se puede observar es que este archivo verifica si le llega un parámetro llamado msg_error (con la función isset() de php) y en base a ese parámetro (en realidad es un código de error) muestra un mensaje de error. A continuación muestro un pantallazo como se ve el formulario en el navegador Chrome:
Pantalla de Login

Y en caso de que el usuario introduzca un nombre de usuario incorrecto se mostrara esta pantalla:
Pantalla Login, error usuario

Como se observa se ven mas atractivas las alertas con JQuery y ademas es sumamente fácil utilizarlas.

validarUsuario.php
Este archivo es el que se encarga de recibir los datos del archivo index.php y los compara contra los que están en la BD. Si el usuario y el password son correctos (existen en la BD) guarda el id del usuario en un formulario (el dato se envía oculto, hidden), inicializa una sesión , guarda algunas variables en dicha sesión y redirecciona hacia el archivo principal.php el cual es la pagina web que se supone debe mostrarse para usuarios registrados. En caso de que el usuario y/o password sean incorrectos entonces este archivo guarda igualmente un codigo de error en un formulario y redirecciona a la pagina de login, es decir, al archivo index.php.

A continuación se muestra su código fuente:

Como se observa; la mayoría del código esta comentado por lo que me ahorrare volver a explicar: Lo que si quiero mencionar es que en la linea 40 he dejado un comentario (CÓDIGO DE SESIÓN), en esa linea si usted quiere puede generar un identificador de sesión, debido a que el ID de sesión de PHP a veces se pierde; usted puede crear un ID mas seguro; por ejemplo con base a la fecha y hora actual. la función session_id() permite leer o asignar el ID de la sesión.

La función session_start() permite iniciar una sesión o continuar una ya iniciada. Es por eso que en todas las paginas web que requieran que el usuario este autenticado se llama a esta función de PHP, esto lo podrás ver en los demás archivos que mostrare mas adelante.

En la linea 37 a 39 se observa que es muy fácil crear una variable de sesión con ayuda del array global $_SESSION[], basta con agregar un nuevo ítem y asignarle un valor, así de fácil. Posteriormente se pueden utilizar en cualquier pagina php por ejemplo para mostrar el Id del usuario y su Status en el navegador:

Facil ¿No?. Continuemos…

En la linea 12 del archivo validarUsuario.php se inserta un archivo llamado conectar_bd.php el cual se encarga de conectar con el DBMS, este archivo es el que muestro a continuacion…

conectar_bd.php

Como se observa primero se definen los datos de conexión en variables locales a la función conectar_bd(). y posteriormente estas variables se usan como parámetros para llamar a la función mysql_connect(), la cual es la que hace la petición al DBMS para conectarse. La función mysql_connect() devuelve un link que representa la conexión establecida al dbms, con este link guardado en la variable $conexio se selecciona la BD a utilizar (linea 24).

principal.php
Este archivo es la pantalla que el usuario ve si se logueo correctamente, nada mas como ejemplo he creado una muy sencilla. Cuando el usuario accede a esta pagina web se supone que ya paso por la pantalla de login y sus datos fueron verificados en la BD. Pero por seguridad antes de mostrarla verifico que efectivamente este logueado a través de las variables de sesión que fueron creadas en el archivo validarUsuario.php.

A continuación muestro el código fuente:

Como decía en la lineas anteriores, cuando una pagina esta restringida lo primero que se debe hacer es verificar que el usuario esta logueado y tiene permisos para ver dicha pagina. Como dije que no mostraría como dar permisos a los usuarios, en este ejemplo solo se comprueba que haya una sesión iniciada y que exista entre las variables de sesión un UID (User Id); Id del usuario en la Base de datos.

Si se verifica que esas condiciones se cumplen entonces se obtienen los datos del usuario, tal como su nombre , correo electrónico, etc. Yo solo saque su nombre completo y lo mostré en la esquina superior derecha para que el usuario tenga la sensación que a entrado al portal. A continuación muestro un pantallazo de este archivo en el navegador:

Pantalla de inicio del usuario logueado

Como se observa también se ha puesto al usuario un link para que cierre su sesión.

Seguridad

Imaginemos que un usuario malintencionado escribe directamente la URL de este archivo en su navegador (escribe http://localhost/autenticar_usuarios/principal.php) pensando que con esto puede entrar y ver el contenido del sitio. Perderá su tiempo pues para eso precisamente se hace la validación al inicio y solamente vera un mensaje de error como el que se ve a continuación:

Mensaje de error al entrar a pagina principal sin login

cerrarSesion.php
Este archivo es al que apunta el enlace “Cerrar sesión ” que esta a un lado del nombre de usuario (una vez que ha iniciado su sesión). Este archivo se encarga de destruir todas las variables de sesión y terminar la sesión; todo esto se hace con las funciones que PHP ya trae incluidas.

Como se ve es muy corto el archivo. No doy mas explicacion ya que cada instruccion esta comentada.

recuperarPassword.php
En la pagina de login, si observas hay un link que dice Olvide mi contraseña, este link nos manda al archivo recuperarPassword.php. Este archivo permite enviar un nuevo password al usuario, el usuario solo debe escribir su correo electrónico y automáticamente se generara un nuevo password de nueve caracteres y se le enviara a dicho email. Obviamente que el correo proporcionado se valida que exista en la BD; Como se observa en la BD el password esta cifrado en MD5 por lo que es necesario proporcionarle otro; no hay forma descifrar el password anterior.

Primero que nada una imagen de la pantalla que se muestra al abrir el archivo recuperarPassword.php:
Pantalla de recuperacion de password

Para mas seguridad el password nunca se muestra al usuario, por el contrario; se le asigna otro (formado aleatoriamente) y se le envía por correo electrónico. Como se observa en la linea 58 se comienza comprobando si llega un parámetro llamado ‘correo’; si llega esto quiere decir que el formulario de recuperación de password ya fue enviado y el correo que esta llegando es de un usuario al que se le debe asignar un nuevo password. Por el contrario; sino llega, se dibujan dos cajas de texto para permitir al usuario escribir su correo electrónico y se le pueda enviar su password.

Bueno, supongamos que a este archivo le llega el parámetro correo, entonces de la linea 65 a la linea 81 se comprueba si ese email existe en la BD. Si no existe, entonces se redirecciona al usuario a este mismo archivo pero con un código de error, el cual servirá para mostrar un texto al usuario avisando que su correo electrónico no existe. En caso de que si exista el email en la BD (no se cumple la condición de la linea 73) entonces se recuperan los datos del usuario (linea 83 a la 85) y posteriormente se le genera un nuevo password (linea 88 ), observe la forma como he generado el nuevo password; se manda a llamar a la función obtenToken($longitud) que esta definida en el archivo generar_token.php del cual hablare mas adelante.

Y ya por ultimo se le envía el password a su correo electrónico del usuario (linea 90 a la linea 139). Algo que me gustaría resaltar es que el nuevo password debe ser actualizado en la BD para que la próxima vez el usuario intente iniciar sesión pues este password sea valido, ademas, solo se debe de actualizar después de notificar al usuario (envió de email correcto), tal como se hace en este ejemplo.

A continuación pongo una imagen del error que aparece en caso de que el email escrito no exista:
Error email inexistente al recuperar password

Mensaje en caso de que el email haya sido enviado correctamente:
Pantalla de email enviado correctamente

Ya no pongo el mensaje del error en caso de que NO se envié el email (falle la función mail() de php), porque es muy obvia, pero, a continuación dejo una imagen del Email que le llega al usuario, con sus nuevos datos de acceso:
Email con el nuevo password del usuario

En la linea 63 del archivo recuperarPassword.php se inserta el archivo generar_token.php el cual contiene algunas funciones para generar tokens de seguridad. Este mismo archivo lo explique en un articulo previo a este, te recomiendo leer el articulo para comprender su funcionamiento. A continuación pongo el código fuente de este archivo:

generar_token.php

Registro de usuarios

A petición de muchos de los visitantes que preguntan (ya sea en privado o en comentarios de esta entrada) como registrar usuarios en php decidí exponer un ejemplo. En la pantalla de Login si observas aparece un enlace (hipervinculo) con la leyenda Deseo registrarme; el código que muestro a continuación es del archivo que se muestra en el navegador al dar click en dicho enlace. Este archivo, en resumen, muestra un formulario creado con HTML para que el usuario capture sus datos personales y datos de acceso (username y password) envié dichos datos al script guardarRegistro.php que guarda los datos en la base de datos. El codigo es este…

registro.php

Como puedes observar esta un poco extenso (como 200 lineas sin lineas en blanco); ese es el precio de validar de una manera rigurosa los datos que el usuario introduce en los cuadros de texto. Tratare de explicar un poco este archivo, pero antes te muestro una imagen de la pagina web que se genera a partir del código fuente anterior:
Pantalla de registro de usuarios

De la linea 10 a 16 se declaran y limpian variables, una para cada dato del usuario que se va a registrar, enseguida en la linea 18 se verifica si esta llegando (si existe, con isset()) la variable de str_nombre, si se cumple que si existe dicha variable; hay una variable con el mismo nombre que se declaro antes (linea 10), entonces se le asigna el valor que llega. Cuando llegan datos significa que ya se habían enviado los datos al archivo guardarRegistro.php y éste los esta regresando si no los pudo guardar. Esta operación la realiza para cada dato del usuario.

Si continuamos viendo el código se observa que de la linea 50 a la 117 es codigo javascript donde ajustamos parámetros del plugin de validación de JQuery. A este tipo de validación se le conoce como validación del lado cliente, en este caso el cliente es el navegador.

En la linea 124 se observa que esta escrito el encabezado del formulario y en su parametro action estamos diciendole que envie los datos de dicho formulario al archivo guardarRegistro.php el cual se encargara de guardarlos en la base de datos (no sin antes validarlos en el lado servidor).

En la linea 141 estamos verificando si existe/llega una variable llamada error y en caso de que si, mostramos la lista de errores que ocurrieron al guardar. La lista de errores vienen en otra variables llamada msg_error. Observa como en la linea 146 y 150 se abre y cierra, respectivamente una lista desordenada de HTML, la variable msg_error trae los <li> </li> correspondientes, cada <li> es un error que ocurrió al intentar guardar en el archivo guardarRegistro.php. En caso de que hayan ocurrido errores se mostrara una pantalla similar a esta:
Error de validación de datos al registrar usuario

guardarRegistro.php

Este archivo recibe los datos del archivo registro.php y los guarda en la base de datos. Antes de guardar realiza varias validaciones, mas abajo esta la explicación pero, veamos el código…

Empezamos recogiendo en variables locales a este archivo los datos que nos llegan del archivo registro.php, esto se hace de la linea 8 a la l6. Después definimos 4 funciones, las cuales mas adelante nos servirán para hacer validaciones con los datos que acabamos de recibir. Cada una tiene un breve explicación así que me ahorrare volver a hacerlo.

De la linea 64 a la 99 validamos que los datos que llegan no vengan vacíos (en blanco), ademas para algunos campos como el username y password validamos su tamaño. Observa como para cada campo que pudiera venir vació o no cumplir el tamaño se siguen revisando los demás pero se agrega un ítem <li> con la descripción del error. En la linea 104 se revisa si la lista NO esta vacía, sino esta vacía entonces regresamos todos los datos al archivo registro.php, para que el usuario no tenga que volver a escribirlos y solo corrija los que tienen error, y ademas mandamos una variable llamada error y la lista de errores que ocurrieron (con su descripción). Ademas de mandar los errores debemos detener la ejecución de este archivo, esto se hace en la linea 124.

Supongamos que no hubo errores de campos en blanco ni tamaños, entonces no se cumplirá la condición de la linea 104, entonces, el interprete de PHP se saltara hasta la linea 126 y continuara su ejecución…

Lo que haremos ahora sera validar que el nombre de usuario y el email escritos no existan en la BD, si algunos de los dos ya fue registrado volveremos a direccionar la ejecución al archivo registro.php para que escriba otro username/password. Esto se hace de la linea 151 a 221, el código esta comentado por lo tanto evitare redundar en la explicación.

Tal y como dice la linea 224, si la ejecución llega hasta dicha linea es que todos los datos son validos (han pasado las validaciones), entonces procedemos a darlo de alta en la base de datos. Después de formar la sentencia SQL (insert) de la linea 230 a la 247, se ejecuta (linea 254) y con lo cual el usuario ha sido dado de alta. Observa como en varios puntos del script voy guardando un log de la ejecución (errores, querys, etc) en una variable llamada $log puedes imprimirla y detener la ejecución en cualquier momento para ver que pasa detrás del telón, observa como lo hago yo en la linea 251 y 252.

Como un plus e puesto el código para que se le puedan enviar sus datos de acceso en un email, si recuerdas ya vimos como enviar un email en PHP en otra entrada de blog. A continuación un pantallazo del email que le llega al usuario que se acaba de registrar:
Email con la confirmacion de registro

Después de enviarle el email con sus datos de acceso, direccionamos al usuario al archivo index.php (recuerda que ahi dio click en el enlace Deseo registrarme) junto con una bandera; $status_registro si esta bandera llega con valor 1 significa que el registro fue exitoso. el archivo index.php ya esta preparado para revisar si le llega esta bandera (fíjate en linea 102). Pantalla de aviso que ha sido registrado:
Aviso de registro exitoso

Por ultimo no hay que olvidarse de cerrar la conexión a la base de datos, esto lo hago en la linea 304 del archivo guardarRegistro.php.

Demo

Si deseas ver el ejemplo funcionando Da click aquí, usa estos datos para probar el ejemplo, Usuario: visitante_wp, Contraseña: 12345. Por motivos de seguridad, solo esta habilitado el inicio de sesión, ni la recuperación de password ni el registro funcionan.

Bueno, eso es todo, si deseas obtener el código fuente del ejemplo, desde GitHub te los puedes descargar:
Descargar ejemplo, hay varios ejemplos, la carpeta se llama autenticar_usuarios.

Por otra parte, ¿Podrías regalarme un like si te gusto el articulo?.

Hasta pronto,
Saludos.

9 Comments

  1. ¡¡Que excelente post!!
    Muy completo y fácil de entender. Felicito ampliamente a notaspro por su tiempo y dedicación a la instrucción a las personas. Muy pocos amigos son tan compartidos. Nuevamente felicitaciones…

  2. Hola Gonzalo, ante todo darte las gracias por tus explicaciones… antes tenía un sistema de login de usuarios con la contraseña sin cifrar, y lo he cambiado con tu ejemplo y funciona perfectamente; el único inconveniente lo tengo a la hora de cambiar el password, cuando hago una recuperacion de la contraseña, no coinciden los valres en md5, es decir, yo cifro con phpmyadmin y veo el valor cifrado, si cifro manualmente pasw=md5(‘password’) los valores no coinciden cuando se insertan en la BD y por ello no pueden recuperar la contraseña… se te ocurre algo?
    También comentar que he cambiado el sistema de envío, en lugar de la función mail, usar autenticación smtp.
    Un saludo

  3. Perdona Gonzalo, solucionado… un pequeño error en el codigo al mandar el mail por smtp, unas comillas se sumaban al final de la contraseña y por eso no coincidian los cifrados, mil disculpas.

  4. Miguel Cadillo Bolivar

    Hola, Gracias estimado, Todo corre chevere pero tengo un problema y esque no me funciona la opción de olvide mi contraseña, nunca me llega la contraseña al correo.

    • tienes que tener el servidor de correo que se menciona en el post.

  5. Frank Luis Figueredo Castillo

    Excelente tutorial amigo, mucgas gracias me ayudo mucho..
    Saludos

  6. Iván

    Que tal, excelente aporte (Y)
    Solo una pregunta, como puedo hacer que los usuarios normales (2) entren a otra pagina???

  7. Jose

    Hola,

    A mi no me muestra los mensajes de alerta de jquery, cuando meto un usuario incorrecto etc. ¿Por qué puede ser? podría alguien decirme donde encontrar los archivos que apunta de js y css

  8. JULIO LEON

    Amigo, mega excelente el tutorial.
    Mil gracias por tan buena explicación y el material.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *