• Publicidad

Problema al cerrar sesión (CGI::Session)

Aquí encontrarás todo lo que sea específicamente acerca de módulos de Perl. Ya sea que estás compartiendo tu módulo, un manual o simplemente tienes una duda acerca de alguno.

Problema al cerrar sesión (CGI::Session)

Notapor thegame » 2012-11-23 10:10 @465

Buenos días, tengo el siguiente archivo que es donde valido la sesión de usuario de una aplicación web:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. binmode STDOUT, ":encoding(UTF-8)";
  3. use lib '../Modulos/';
  4. #use strict;
  5. #use warnings;
  6. #use diagnostics;
  7.  
  8. use login;
  9. use CGI::Session;
  10. use CGI ':standard';
  11. use CGI::Carp qw'fatalsToBrowser warningsToBrowser';
  12. print error;
  13.  
  14.  
  15. my $cgi = CGI->new();
  16. $cgi->charset('UTF-8');
  17.  
  18.  
  19. my $session = CGI::Session->new("driver:File", $cgi, {'Directory'=>'/tmp/'})
  20.     or die CGI::Session->errstr;
  21.  
  22. $session->expire('+10s'); ##Tiempo que vence la sesión
  23. ## Enviamos la cookie de sesión al usuario
  24. print $session->header;
  25. print "<META HTTP-EQUIV='CACHE-CONTROL' CONTENT='NO-CACHE,NO-STORE,PRIVATE'>";
  26. print "<META HTTP-EQUIV='PRAGMA' CONTENT='NO-CACHE'>";
  27.  
  28. # Aquí guardaremos el perfil del usuario
  29. my $perfil;
  30.  
  31. if ( not $session->param('~registrado') ) {     # si el usuario no está registrado
  32.  
  33.     # vemos si se está registrando en este momento
  34.     if (my $nombre = $cgi->param('login_nombre')) {
  35.         my $passwd = $cgi->param('login_passwd');
  36.  
  37.         # Vemos si es un usuario conocido por nosotros
  38.         # si lo es, obtenemos su perfil
  39.         if ($perfil = login->verificar($nombre, $passwd)) {
  40.  
  41.             # Guardamos el perfil asociado a la sesión
  42.             $session->param('perfil', $perfil);
  43.             $session->param('~registrado', 1);
  44.             $session->expire('~registrado', '+10s');
  45.         }
  46.         else {  # Es un desconocido, le pedimos que rellene el registro otra vez
  47.             presenta_login('Usuario o contrase&ntilde;a incorrecta');
  48.             exit;
  49.         }
  50.     }
  51.     else {      # No está registrado ni se está registrando
  52.        presenta_login('Identif&iacutequese');
  53.        exit;
  54.  
  55.     }
  56. }
  57. else {          # es un usuario registrado (hay una sesión de él)
  58.     # recuperamos el perfil, desde la sesión
  59.     $perfil = $session->param('perfil');
  60.  
  61. }
  62.  
  63.  
  64.  
  65. # A partir de aquí, sabemos qué usuario es, y su perfil
  66. # Podemos presentarle las opciones propias de un usuario registrado
  67. my $nombre = $perfil->{nombre};
  68. my $nom_usuario  = $perfil->{login};
  69.  
  70. if ($cgi->param('Desconectar')) {       # caso de que el usuario quiera desconectarse
  71.         $session->clear(['~registrado']);   # olvidamos que estaba registrado
  72.         $session->flush();
  73.         CGI::Session->find('driver:file', sub {}, {Directory => '/tmp/'} );
  74.         print p("<META HTTP-EQUIV=\"Refresh\" CONTENT=\"1;URL=info.pl\" target=\"_SELF\"/>");
  75.  
  76. }
  77. else {          # una página normal
  78.  
  79.    #$session->header('-cache-control' => 'NO-CACHE');
  80.  
  81.    print
  82.         start_html({-tittle=>'Bienvenido',-style=>'../../Css/style_formulario.css'}),
  83.         p(div({-id=>"Titulob"},"Bienvenido $nombre ($nom_usuario)")),
  84.         p(a({-href=>"formulario_contacto.pl", -TARGET=>"info"},div({-id=>"menu2"},'Agregar Contacto')),
  85.         a({-href=>"modf.pl", -TARGET=>"info"},div({-id=>"menu2"},'Modificar Contacto')),
  86.         a({-href=>"formulario_institucion.pl", -TARGET=>"info"},div({-id=>"menu2"},'Agregar Instituci&oacute;n')),
  87.         a({-href=>"formulario_sede.pl", -TARGET=>"info"},div({-id=>"menu2"},'Agregar Sede')),
  88.         a({-href=>"formulario_usuario.pl", -TARGET=>"info"},div({-id=>"menu2"},'Agregar Usuario')),
  89.         a({-href=>"eliminar_usuario.pl", -TARGET=>"info"},div({-id=>"menu2"},'Eliminar Usuario')),
  90.         a({-href=>$cgi->url() . '?Desconectar=1', -onClick=>''},div({-id=>"menu2"},'Salir'))),
  91.         end_html()
  92.         ;
  93. }
  94. sub presenta_login {
  95.         my $titulo = shift;
  96.  
  97.         my $javas=<<EOC
  98.                 function CambiaColor(){
  99.                         if ("$titulo" == "Usuario o contrase&ntilde;a incorrecta"){
  100.                                 document.getElementById('subt').style.color = "red";
  101.                                                                                 }
  102.                                         }
  103. EOC
  104. ;
  105.         print
  106.         start_html({-tittle=>'Login',-style=>'../../Css/login.css', -script=>$javas, onLoad=>'CambiaColor()'}),
  107.         div({-id=>"cuadro"},div({-id=>"titulo"},'Registro de entrada'),
  108.         div({-id=>"subt"},$titulo),
  109.         start_form(),
  110.         div({-id=>'nombre'},'Nombre: '     . textfield('login_nombre')),
  111.         div({-id=>'pass'},'Contrase&ntilde;a: ' . password_field('login_passwd')),
  112.         p(),
  113.         submit('Entrar')),
  114.         end_form,
  115.         end_html()
  116.         ;
  117. }
  118.  
  119.  
Coloreado en 0.008 segundos, usando GeSHi 1.0.8.4



Por cierto este código es tomado del amigo explorer (y con algunas modificaciones) que escribió en otro mensaje (gracias).

El problema es que cuando presiono el enlace de "salir" ejecuta el $session->clear pero vuelve a crear la sesión inmediatamente y después redirecciona. Por favor, no entiendo el porqué crea la sesión de nuevo.

Gracias por adelantado de la ayuda que me puedan dar.
thegame
Perlero nuevo
Perlero nuevo
 
Mensajes: 38
Registrado: 2011-11-08 11:19 @513
Ubicación: Venezuela

Publicidad

Re: Problema al cerrar sesión (CGI::Session)

Notapor explorer » 2012-11-23 12:30 @562

¿Qué quieres decir con que redirecciona?

En el código vemos que se manda un print() que refresca y redirecciona la página a la principal, dentro del if() del 'Desconecta'. ¿Te refieres a eso?

Y al volver a cargar la principal, se vuelve a crear una sesión (línea 19), por lo que debería salir el mensaje de 'Identifíquese' otra vez.

No importa que la sesión se cree de nuevo. Lo importante es si el usuario se identifica o no.

Naturalmente, estos son líneas de programa y procedimientos. Si no quieres que se cree una sesión nueva, quizás debas redireccionar a una página estática cuando el usuario se desconecta.

No sé si te he respondido bien...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problema al cerrar sesión (CGI::Session)

Notapor thegame » 2012-11-23 13:28 @603

Hola explorer. Sí, me refiero al if() de 'desconecta'. Es que el problema es ese: yo salgo a 'info.pl' y ahí existe un enlace para el login y cuando haces clic entra directo sin pedir autenticación. Además cuando doy 'atrás' en el navegador regresa al menú.

Otra pregunta ese print() que redirecciona (en el if() 'desconecta'). Yo lo había colocado $cgi->redirect('info.pl') pero no me redirecciona, hay otro método para redireccionar o estoy escribiendo mal el código.
thegame
Perlero nuevo
Perlero nuevo
 
Mensajes: 38
Registrado: 2011-11-08 11:19 @513
Ubicación: Venezuela

Re: Problema al cerrar sesión (CGI::Session)

Notapor explorer » 2012-11-23 16:54 @746

No estoy muy seguro de por qué puede fallar...

En cuanto al redirect(), debería ser (que yo recuerde):

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     print $cgi->redirect('info.pl');
  2.     exit;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


El problema es que tienes puesto unos print() antes, en las líneas 25 y 26, así que no funcionará el redirect() hasta que no las quites. Ese contenido es mejor que lo pongas dentro de la creación de las distintas páginas (en el start_html() de cada una).

No es nada bueno mezclar print() con funciones generadoras de HTML y el header(), si no se sabe exactamente el orden de salida de cada uno de ellos.

En caso de duda, ejecutar el cgi en la línea de comandos, para ver el resultado en pantalla.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problema al cerrar sesión (CGI::Session)

Notapor thegame » 2012-11-26 09:03 @418

Ok, bueno una última pregunta. ¿Cómo hago para que al dar atrás en el navegador me pida de nuevo autenticación? Porque aunque la sesión haya expirado igual puedo regresar presionando "atrás " en el navegador.
thegame
Perlero nuevo
Perlero nuevo
 
Mensajes: 38
Registrado: 2011-11-08 11:19 @513
Ubicación: Venezuela

Re: Problema al cerrar sesión (CGI::Session)

Notapor explorer » 2012-11-26 10:29 @478

Pero al volver a atrás, ¿qué estamos viendo? ¿realmente se ha cargado de nuevo la página (ha habido una petición al servidor), o el navegador web nos está mostrando el contenido del caché?

Si la sesión ha expirado, debería aparecer una nueva autenticación. Quizás no se ha borrado del todo los datos de sesión, y aunque la cookie haya expirado, CGI::Session se esté encontrando con una sesión abierta que corresponde con la IP del mismo usuario.

Humm... habría que reducir el código a la mínima expresión, para hacer pruebas...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problema al cerrar sesión (CGI::Session)

Notapor thegame » 2012-11-28 10:28 @478

Hice una prueba para que cuando haga clic en salir se vaya al siguiente archivo:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use CGI;
  3. use CGI::Session;
  4. use CGI ':standard';
  5. use CGI::Carp qw'fatalsToBrowser warningsToBrowser';
  6. print error;
  7.  
  8. my $cgi = CGI->new();
  9. $cgi->charset('UTF-8');
  10.  
  11. my $session = CGI::Session->load() or die CGI::Session->errstr;
  12.  if ( $session->is_empty ) {
  13.         print $session->header;
  14.         $session->flush();
  15.         CGI::Session->find('driver:file', sub {}, {Directory => '/tmp/'} );            # Purgamos sesiones caducadas
  16.         $session->delete();
  17.     }
  18.  
  19.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


En esta prueba el reconoce que la sesión ha expirado (lo intenté poniendo un print y funcionó) pero no me borra la sesión...

Ahora ¿cómo hago para "meter" esta líneas en el cgi?

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. print "<META HTTP-EQUIV='CACHE-CONTROL' CONTENT='NO-CACHE,NO-STORE,PRIVATE'>";
  2. print "<META HTTP-EQUIV='PRAGMA' CONTENT='NO-CACHE'>";
  3.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Lo que quiero es no se guarde nada de la página en caché. Con esto creo que sí resolvería lo de volver con el botón de 'atrás' en el navegador (que se guarda en caché, por cierto).
thegame
Perlero nuevo
Perlero nuevo
 
Mensajes: 38
Registrado: 2011-11-08 11:19 @513
Ubicación: Venezuela

Re: Problema al cerrar sesión (CGI::Session)

Notapor explorer » 2012-11-28 17:33 @773

La clave está en el uso de un parámetro, dentro de la sesión, que indica su estado (son los parámetros que comienzan por '~' en los ejemplos anteriores). Si el valor del parámetro es '1', seguimos dentro, pero si no, aunque la sesión exista, no es una sesión válida, ni podemos considerar el usuario como autenticado.

Ahora bien... si resulta que el usuario da 'atrás', y adonde va hacia atrás es justo en el formulario donde ingreso los datos de autenticación, entonces es normal que el formulario mantenga los datos que contenía el formulario unos momentos antes.

Solución: una vez que el usuario se da baja, lo llevamos a otra página, o... lo llevamos a la misma página del formulario de entrada. El que aparezca en ese momento, en la caja de registro y contraseña, los datos del usuario, es porque éste le dijo al navegador que se los recordara (los navegadores pueden recordar esos datos, según las preferencias de los usuarios).

El insertar los datos de no-caché solo sirve para que el navegador vuelva a pedir los archivos HTML e imágenes de esa página, en cada petición. Pero en los CGI, eso siempre ocurre (el navegador podría cachear el resultado del CGI, pero sabe que es un programa, así que siempre lo solicita: no lo cachea).

Aunque estoy sospechando que se puede hacer de una forma más cómoda, tienes una solución completa en el último mensaje de este hilo. Aunque es un mensaje muy largo, lo importante es el último código: la clave está en la línea 47: si la sesión ha expirado, el parámetro '~registrado' tiene un valor de falso. En ese momento, le decimos al usuario que su sesión ha expirado (o cerrado), y le volvemos a mostrar el formulario de entrada. Fíjate que incluso le saludamos con su nombre: en la línea 49 extraemos su nombre de la propia sesión. Es decir: existe la sesión, pero el parámetro '~registrado' ya nos dice que caducó.

Hay además dos tiempos de expiración: el tiempo que dura registrado el usuario, son diez segundos, pero la sesión dura un día. Dicho de otra manera: durante un día el servidor recuerda los datos del usuario, pero cada vez que entra solo le deja estar diez segundos.

Te animo a que lo pruebes. Date cuenta que no es igual al primer código que publicaste en este hilo. Aunque decías que estaba basado en un código mío, yo considero que el correcto es el último publicado en el hilo enlazado antes.

Voy a apuntar aquí los enlaces a más información sobre CGI::Session, con ejemplos característicos:
En este último, hay un ejemplo llamado MEMBERS AREA, donde protegemos una zona de la web a solo la gente que esté autenticada. Y usan un parámetro llamado '~logged-in' para controlar el estado de el usuario. Precisamente de este ejemplo construí el mío.

Vigila también los tiempos de expiración de las sesiones: si el tiempo es largo, la cookie sigue transmitiéndose al servidor. De hecho, esta es una forma de terminar la sesión de un usuario: mandando un tiempo de expiración negativo o cero, con lo que la cookie de sesión, en el navegador del usuario, se borra.

Si te parece, podemos construir una minimaqueta de lo que quieres hacer. Has hablado de una página de registro del usuario (autenticación), otra página de acceso solo para usuarios autenticados, y el botón de cerrar sesión. Y el problema estaba en si el usuario pulsa el botón de vuelta atrás. ¿Se me olvida algo?

P.D. Sí, esto es un rollo. En Mojolicious y Dancer lo han simplificado para hacerlo más transparente.
P.P.D. Si quieres realmente evitar que las páginas de contenido no queden almacenadas en la caché del navegador, entonces sí que hay poner lo del no-cache, pero solo en esas páginas.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problema al cerrar sesión (CGI::Session)

Notapor thegame » 2012-11-29 08:41 @403

Gracias por tomarte el tiempo para la explicación, explorer.

Tomé el código que me indicaste y lo adapté a lo que necesitaba (solo cambié el formulario de autenticación y lo que aparece cuando estás dentro luego que entras) Ahora cuando presiono salir, envío a la página principal, y si vuelvo a entrar al área para usuarios autenticados me pide contraseña de nuevo (el tiempo de expiración cuando estás autenticado sigue en 10 segundos como en el ejemplo que me distes) Muy bien :D

Ahora el problema sigue siendo cuando estoy en la página principal y presiono 'atrás': me regresa al área de usuarios autenticados.

Sin embargo, hice una prueba que fue estando en la página principal borrar la cookie desde el navegador y cuando presioné atrás me dijo que la página había expirado (estoy usando Firefox). Ahora, yo opino hacer la prueba de no guardar en caché la página.

¿¿Cómo escribo en cgi lo del no-cache??
thegame
Perlero nuevo
Perlero nuevo
 
Mensajes: 38
Registrado: 2011-11-08 11:19 @513
Ubicación: Venezuela

Re: Problema al cerrar sesión (CGI::Session)

Notapor explorer » 2012-11-29 09:00 @416

Lo debes escribir dentro del start_html() (sacado del manual del CGI, sección 'CREATING THE HTML DOCUMENT HEADER'):

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. print start_html(
  2.     -title   => 'Secrets of the Pyramids',
  3.     -author  => '[email protected]',
  4.     -base    => 'true',
  5.     -target  => '_blank',
  6.     -meta    => {
  7.                  'keywords'  => 'pharaoh secret mummy',
  8.                  'copyright' => 'copyright 1996 King Tut',
  9.                 },
  10.     -style   => {
  11.                  'src'       => '/styles/style1.css',
  12.                 },
  13.     -BGCOLOR => 'blue',
  14.     -head    => [
  15.                  meta({
  16.                        -http_equiv => 'Cache-Control',
  17.                        -content    => 'no-cache,no-store,private',
  18.                  }),
  19.                  meta({
  20.                        -http_equiv => 'Pragma',
  21.                        -content    => 'no-cache',
  22.                  }),
  23.                 ],
  24. );
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
(Naturalmente, hay muchos campos que puedes quitar, el único interesante para tu caso es del '-head'. Si lo ves complicado, puedes seguir usando la solución que tenías, con unos simples print(), pero eso sí: deben ir justo en la parte del <head> de la página.)

De todas maneras... pienso que debe haber una manera mejor de evitar la vuelta atrás... En el propio manual del CGI se comenta el parámetro -expires, que indica el tiempo por el cuál se puede mantener la información creada por el CGI dentro de la caché del navegador. Por defecto, los navegadores no cachean nada generado por los CGI, pero con esa opción se puede hacer que la guarden durante un momento, y luego, que la descarten. Mira que es justo lo contrario de lo que quieres hacer, pero quizás podría ser aplicado.

A ver si tengo un rato, y puedo hacer una prueba.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Siguiente

Volver a Módulos

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados