martes, 10 de noviembre de 2015

Autenticar usuario y guardar en una cookie con PHP

Vamos a crear un sistema para autenticar usuarios con PHP, con la particularidad que este sistema va a ofrecer al visitante la opción de guardar su usuario, para que la página lo recuerde en sucesivos accesos y no tenga que volver a autenticarse. El usuario se guardará en una cookie para que el navegador pueda recordarlo en sus distintas visitas. 


Esta es una opción muy útil para que el visitante no tenga que estar todo el tiempo autenticándose, con su usuario y contraseña, cada vez que accede a la página web. Seguro que es una opción que habremos visto en un montón de sitios web. 

Este artículo hace continuación de una serie de talleres y ejemplos que hemos visto anteriormente en el manual de Autentificación de usuarios en PHP. En este taller no vamos a realizar una autenticación muy elaborada, sino una muy simple, para facilitar el desarrollo. Luego la complejidad la aportará la parte de guardar el usuario en una cookie, que no es difícil de hacer, pero sí requiere de nuevos conocimientos que aplicar. 

Explicación de almacenar el usuario en una cookie 

Primero vamos a explicar con palabras el modelo de trabajo que vamos a aplicar para almacenar el usuario en una cookie. No he investigado cómo lo podrán hacer esto otras personas en otros desarrollos, pero creo que he ingeniado una forma adecuada para hacerlo. 

Digo esto porque lo primero que se me ocurrió fue meter el nombre de usuario y la clave en unas cookies. Sería simplemente crear un par de cookies en el sistema del usuario con esas dos variables. Pero luego pensando, no me parecía muy atractiva la posibilidad de incluir esa información sensible en unas cookies en el ordenador del usuario, por su hubiera alguna persona que pudiera leerlas, copiarlas y utilizarlas en otro ordenador. Igual no me debería preocupar por ello, pero en cualquier caso no me gustaba la posibilidad de almacenar el nombre de usuario y contraseña, sino almacenar otro tipo de información menos crítica. 

Entonces lo que se me ocurrió es almacenar el identificador del usuario. Pero claro, si alguien conseguía crear una cookie en el sistema con cualquier identificador de usuario, podría acceder a la cuenta de ese usuario. Así que había que aplicar otra estrategia adicional para asegurar que ese identificador de usuario no se pueda reproducir. Finalmente, decidí generar un número aleatorio cuando el usuario se conecta a la página y se autentica correctamente, y almacenarlo en dos sitios, primero en el registro del usuario en la base de datos y luego en la cookie. 

Así, cuando el visitante decide que quiere que el sitio web le recuerde su cuenta de usuario, para no tener que volver a autenticarse en siguientes accesos, se guardan dos cosas en las cookies del navegador: su identificador de usuario y una marca aleatoria (dicha marca también se almacena en la base de datos, asociada a su usuario). En siguientes accesos primero se comprueba si existen esas cookies en el navegador del visitante y si el conjunto de identificador de usuario y la marca aleatoria almacenados en la cookie coincide con lo que tenemos en la base de datos. 

Dicho de otra manera, en la cookie guardamos el identificador de usuario. Además, generamos un número aleatorio que guardamos en dos sitios: 1) en la tabla de usuario, en el registro correspondiente al usuario que desea que se le recuerde la clave y 2) en una cookie. Luego cuando el usuario se conecta de nuevo, no sólo se comprueba que tenga la cookie con el identificador de usuario, sino que tenga la otra cookie con la marca aleatoria y que sea la misma que tenemos en la base de datos para ese mismo usuario. 

Espero que el sistema se pueda entender. No obstante, espero clarificarlo aun más a medida que explique el código PHP y la base de datos que vamos a utilizar. 

Tabla de usuario 

En la tabla de usuario que hemos creado para este ejemplo tenemos 4 campos:

  • Identificador de usuario
  • Nombre de usuario
  • Clave de acceso
  • Marca aleatoria que se ha metido en la cookie

Para el ejemplo hemos creado la tabla e insertado un par de usuarios para hacer pruebas. Tendrá una forma como esta: 




Código de la página PHP 

Ahora voy a explicar por partes el código PHP para autenticar al usuario y guardar la información de acceso en la cookie, así como la parte de comprobar si el usuario tenía la cookie con su acceso guardado en el ordenador. 

Primero vamos a empezar mostrando el formulario HTML: 

<form action="prueba-cookies.php" method="post">
Usuario: <input type="text" name="usuario">
<br>
Clave: <input type="text" name="clave">
<br>
<input type="checkbox" name="guardar_clave" value="1"> Memorizar el usuario en este ordenador
<br>
<input type="submit" value="Entrar">
</form>


Como vemos, tiene los campos para escribir el nombre de usuario y la clave y un campo checkbox adicional para que el usuario marque si quiere que su acceso se guarde en su ordenador. 

Ahora voy a mostrar el código que utilizaríamos para recibir por post, del formulario de autentificación, el nombre de usuario y contraseña. Este código también tiene que detectar si el usuario quería que se guardase su acceso en el ordenador. 

//debería comprobar si el usuario es correcto
$ssql = "select * from usuario where usuario = '" . $_POST["usuario"] . "' and clave='" . $_POST["clave"] . "'";
//echo $ssql;
$rs = mysql_query($ssql);
if (mysql_num_rows($rs)==1){
   //TODO CORRECTO!! He detectado un usuario
   $usuario_encontrado = mysql_fetch_object($rs);
   //ahora debo de ver si el usuario quería memorizar su cuenta en este ordenador
   if ($_POST["guardar_clave"]=="1"){
      //es que pidió memorizar el usuario
      //1) creo una marca aleatoria en el registro de este usuario
      //alimentamos el generador de aleatorios
      mt_srand (time());
      //generamos un número aleatorio
      $numero_aleatorio = mt_rand(1000000,999999999);
      //2) meto la marca aleatoria en la tabla de usuario
      $ssql = "update usuario set cookie='$numero_aleatorio' where id_usuario=" . $usuario_encontrado->id_usuario;
      mysql_query($ssql);
      //3) ahora meto una cookie en el ordenador del usuario con el identificador del usuario y la cookie aleatoria
      setcookie("id_usuario_dw", $usuario_encontrado->id_usuario , time()+(60*60*24*365));
      setcookie("marca_aleatoria_usuario_dw", $numero_aleatorio, time()+(60*60*24*365));
   }
   echo "Autenticado correctamente";
   //header ("Location: contenidos_protegidos_cookie.php");
   
}else{
   echo "Fallo de autenticación!";
   echo "<p><a href='prueba-cookies.php'>Volver</a>";
}


Para comprobar si los datos de autenticación que recibimos por el formulario son correctos, hacemos una sentencia SQL. La ejecutamos y si nos da como resultado que tenemos un registro encontrado en la tabla de usuarios, es que el nombre de usuario y clave corresponden con el de algún usuario. 

Luego con la línea 

if ($_POST["guardar_clave"]=="1"){

Comprobamos si el visitante había pedido que se almacenase la clave en su ordenador. Entonces hay que generar las cookies correspondientes, que habíamos comentado anteriormente en este artículo. 

Lo hacemos en tres pasos: 


  • Genero un número aleatorio para que nos sirva de marca.
  • Inserto la marca aleatoria en la tabla de usuarios, haciendo un update en el registro del usuario autenticado que habíamos detectado anteriormente.
  • Genero y coloco en el ordenador del usuario las dos cookies para guardar su acceso en el navegador: el identificador del usuario y la marca aleatoria. Hemos creado las cookies para que se almacenen durante un año en el ordenador del usuario. 

    Nota: Es importante señalar que, para colocar o crer cookies en el navegador del visitante, debemos hacerlo antes de que se hayan enviado las cabeceras de http, es decir, antes de haber escrito cualquier texto en la página. Si no, nos podría dar un error de http headers already sent.


    Por último veamos el código PHP para ver si detectamos las cookies en el navegador de un usuario autenticado anteriormente en el sistema y guardado en el ordenador del usuario. 

    //primero tengo que ver si el usuario está memorizado en una cookie
    if (isset($_COOKIE["id_usuario_dw"]) && isset($_COOKIE["marca_aleatoria_usuario_dw"])){
       //Tengo cookies memorizadas
       //además voy a comprobar que esas variables no estén vacías
       if ($_COOKIE["id_usuario_dw"]!="" || $_COOKIE["marca_aleatoria_usuario_dw"]!=""){
          //Voy a ver si corresponden con algún usuario
          $ssql = "select * from usuario where id_usuario=" . $_COOKIE["id_usuario_dw"] . " and cookie='" . $_COOKIE["marca_aleatoria_usuario_dw"] . "' and cookie<>''";
          $rs = mysql_query($ssql);
          if (mysql_num_rows($rs)==1){
             echo "<b>Tengo un usuario correcto en una cookie</b>";
             $usuario_encontrado = mysql_fetch_object($rs);
             echo "<br>Eres el usuario número " . $usuario_encontrado->id_usuario . ", de nombre " . $usuario_encontrado->usuario;
             //header ("Location: contenidos_protegidos_cookie.php");
          }
       }
    }


    Como primer paso compruebo si existen las cookies con el identificador del usuario y la mencionada marca aleatoria. Además, hacemos una comprobación adicional para ver si alguna de las dos cookies contiene un string vacío, porque en ese caso no están guardadas correctamente y no nos sirven. 

    Si todo ha ido bien, miramos en la base de datos si el usuario con identificador determinado en la cookie tiene la marca aleatoria igual que la que tenía la cookie del navegador del visitante. Además, en la consulta en la base de datos también nos aseguramos que la marca aleatoria sea distinta de "", porque entonces es un usuario que nunca había pedido que se guardasen sus datos en el ordenador. 

    Si esa consulta daba un registro, es que corresponde con un usuario que se había almacenado en el ordenador y es el usuario que estaba autenticado anteriormente y guardado su acceso. 

    Conclusión 

    Hasta aquí he comentado todo lo que necesitamos saber para crear la infraestructura para que la página web recuerde la clave del usuario y no tenga que autenticarse cada vez que accede al sitio. El código que hemos mostrado podría completarse con una serie de mejoras o personalizaciones para adaptarlo a nuestras necesidades, pero seguro que sirve de guía para el interesado. 

    Ahora presento el código completo de la página de este ejemplo: 

    <?
    //conecto con la base de datos
    $conn = mysql_connect("servidor","usuario","clave");
    //selecciono la BBDD
    mysql_select_db("base de datos",$conn); 

    //primero tengo que ver si el usuario está memorizado en una cookie
    if (isset($_COOKIE["id_usuario_dw"]) && isset($_COOKIE["marca_aleatoria_usuario_dw"])){
       //Tengo cookies memorizadas
       //además voy a comprobar que esas variables no estén vacías
       if ($_COOKIE["id_usuario_dw"]!="" || $_COOKIE["marca_aleatoria_usuario_dw"]!=""){
          //Voy a ver si corresponden con algún usuario
          $ssql = "select * from usuario where id_usuario=" . $_COOKIE["id_usuario_dw"] . " and cookie='" . $_COOKIE["marca_aleatoria_usuario_dw"] . "' and cookie<>''";
          $rs = mysql_query($ssql);
          if (mysql_num_rows($rs)==1){
             echo "<b>Tengo un usuario correcto en una cookie</b>";
             $usuario_encontrado = mysql_fetch_object($rs);
             echo "<br>Eres el usuario número " . $usuario_encontrado->id_usuario . ", de nombre " . $usuario_encontrado->usuario;
             //header ("Location: contenidos_protegidos_cookie.php");
          }
       }
    }

    if ($_POST){
       //es que estamos recibiendo datos por el formulario de autenticación (recibo de $_POST)

       //debería comprobar si el usuario es correcto
       $ssql = "select * from usuario where usuario = '" . $_POST["usuario"] . "' and clave='" . $_POST["clave"] . "'";
       //echo $ssql;
       $rs = mysql_query($ssql);
       if (mysql_num_rows($rs)==1){
          //TODO CORRECTO!! He detectado un usuario
          $usuario_encontrado = mysql_fetch_object($rs);
          //ahora debo de ver si el usuario quería memorizar su cuenta en este ordenador
          if ($_POST["guardar_clave"]=="1"){
             //es que pidió memorizar el usuario
             //1) creo una marca aleatoria en el registro de este usuario
             //alimentamos el generador de aleatorios
             mt_srand (time());
             //generamos un número aleatorio
             $numero_aleatorio = mt_rand(1000000,999999999);
             //2) meto la marca aleatoria en la tabla de usuario
             $ssql = "update usuario set cookie='$numero_aleatorio' where id_usuario=" . $usuario_encontrado->id_usuario;
             mysql_query($ssql);
             //3) ahora meto una cookie en el ordenador del usuario con el identificador del usuario y la cookie aleatoria
             setcookie("id_usuario_dw", $usuario_encontrado->id_usuario , time()+(60*60*24*365));
             setcookie("marca_aleatoria_usuario_dw", $numero_aleatorio, time()+(60*60*24*365));
          }
          echo "Autenticado correctamente";
          //header ("Location: contenidos_protegidos_cookie.php");
          
       }else{
          echo "Fallo de autenticación!";
          echo "<p><a href='prueba-cookies.php'>Volver</a>";
       }
       
    }else{
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

    <html>
    <head>
       <title>cookies para detectar usuario</title>
    </head>

    <body>

    <form action="prueba-cookies.php" method="post">
    Usuario: <input type="text" name="usuario">
    <br>
    Clave: <input type="text" name="clave">
    <br>
    <input type="checkbox" name="guardar_clave" value="1"> Memorizar el usuario en este ordenador
    <br>
    <input type="submit" value="Entrar">
    </form>
    <br>
    <br>
    <b>Usuarios válidos:</b>
    <br>
    <br>
       User: pepe
       <br>
       Clave: 1234 
       <br>
       <br>
       User: juan 
       <br>
       Clave: 1111 

    </body>
    </html>

    <?
    }
    ?>
  • No hay comentarios:

    Publicar un comentario

    Entradas populares