domingo, 6 de septiembre de 2020

Flask 17. Manejo de Cookies en Flask.

 


Anteriormente. Flask 16. Mostrando mensajes en Flask.


Manejo de Cookies en Flask.


Cuando estamos creando una aplicación o proyecto en Flask se nos puede dar el caso de que tengamos que guardar provisionalmente alguna información en el lado del cliente, es decir que necesitemos gestionar algún dato que nos proporciona el usuario pero desde su lado, sin subirlo al servidor. 

¿Quien no conoce el clásico caso de los carritos de la compra de las páginas web de venta de artículos online?. En ellos seleccionas los productos que quieres comprar y los incluyes en el carrito, para más tarde completar el proceso de compra. Incluso si cierras el navegador y vuelves a esa página más tarde, tu carrito de la compra seguirá ahí conteniendo los productos que ya habías seleccionado. 

Esto se consigue con las cookies. Tal como nos pone la wikipedia: 

"Una cookie es un término que hace referencia a una pequeña información enviada por un sitio web y almacenada en el navegador del usuario, de manera que el sitio web puede consultar la actividad previa del navegador." 

En resumen es una pequeña información que guardamos en el navegador del usuario información que no sea sensible y que después desde el lado del servidor podemos consultar.

Para gestionar cookies en Flask tenemos que afrontarlo en dos pasos. En primer lugar tenemos que establecer el contenido de la Cookie y crearla y en un segundo paso recuperar del servidor el valor de esa cookie.

Guardar una Cookie


Para guardar una cookie tenemos que tener presente, que la información que queremos guardar debe viajar y guardarse en el cliente, por lo tanto debemos devolverla en una respuesta, por lo que vamos a utilizar el objeto respuesta para devolver esa información.

Para crear el objeto respuesta utilizaremos el método make_reponse().

 respuesta = make_response('Hemos guardado la cookie')

A este método make_response() le podemos pasar:

  • Una página
respuesta = make_response(redirect('/'))

Depués de guardar la cookie nos devuelve, en este caso, a la página inicial. 

  • Un contenido en texto
respuesta = make_response('Hemos guardado la cookie')

Guarda la cookie y nos muestra un texto en pantalla. 

  • Json.


Por ser lo más sencillo vamos a pasarle un texto ('Hemos guardado la Cookie'). 

Ahora sobre respuesta aplicaremos la cookie  con el método set_cookie()

respuesta.set_cookie(Key="nombre de la cookie", value="valor a guardar", secure = True)

Pongo el argumento "secure = True" ya que sino, FireFox y otros navegadores aunque no lo muestren directamente,  en opciones del desarrollador nos da la siguiente alerta:

"Cookie “galleta” will be soon rejected because it has the “SameSite” attribute set to “None” or an invalid value, without the “secure” attribute. To know more about the “SameSite“ attribute, read https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite"

Esto también lo podríamos haber hecho usando las opciones de configuración de Flask con:

SESSION_COOKIE_SECURE = True


Bien, ya solo nos quedará devolver el objeto respuesta como return de la petición.

La aplicación de flask podría quedar de esta forma:

from flask import Flask, make_response
app = Flask(__name__)


@app.route('/')
def home():
    return 'Esta es la pagina inicial'


@app.route('/set_cookie/')
def save_cookie():
    respuesta = make_response('Hemos guardado la cookie')
    respuesta.set_cookie('mi_cookie', 'esto se guarda en la cookie', secure = True)
    return respuesta

if __name__ == '__main__':
    app.run(debug=True)

y si la ejecutamos:


Para ver la cookie podemos ir a herramientas del desarrollador web y dentro de la consola veremos nuestra cookie.




Otra opción es chequear la pestaña de almacenamiento dentro de las herramientas del desarrollador, y allí podrás ver la cookie:






Leer una Cookie.


Para recuperar una cookie del navegador, que no es más que una cadena de caracteres, utilizaremos el objeto request.cookies.get de la siguiente forma:

leer_cookie = request.cookies.get('nombre de la cookie')

Nuestro archivo quedaría de la siguiente forma:

from flask import Flask, make_response, request
app = Flask(__name__)


@app.route('/')
def home():
    return 'Esta es la pagina inicial'


@app.route('/set_cookie/')
def save_cookie():
    respuesta = make_response('Hemos guardado la cookie')
    respuesta.set_cookie('mi_cookie', 'esto se guarda en la cookie')
    return respuesta


@app.route('/get_cookie/')
def read_cookie():
    leer_cookie = request.cookies.get('mi_cookie')
    return f'Contenido de la cookie -> {leer_cookie}'


if __name__ == '__main__':
    app.run(debug=True)

y al ejecutarse:


Las Cookies pueden expirar: Los argumentos max_age y expires.


Por defecto, las cookies expiran cuando el usuario cierra la sesión, esto es en cuanto se cierra el navegador. Para conservar una cookie podemos utilizar los atributos expires o max_age.

Cuando se usan ambos max_age tiene preferencia sobre expires. 

En Lugar de expirar cuando se cierra el navegador, las cookies permanentes expiran en una fecha especifica (expires) o tras un periodo de tiempo especifico en segundos (max_age).

Nota: Cuando se establece una fecha de expiración, la fecha y hora que se establece es relativa al cliente en el que se establece la cookie, no del servidor.

Por ejemplo para poner una cookie que se conserve durante 5 minutos podemos usar la siguiente vista:

Cookie con una duración de 5 minutos.

@app.route('/set_cookie5m/')
def save_cookie5m():
    # make_response = La respuesta será 
    respuesta=make_response('Hemos guardado la cookie')
    # en respuesta ira la cookie 'nombre' 'la cookie en si'
    # La duración es max_age es 5 minutos lo que en segundos es 60 s * 5
    respuesta.set_cookie('galleta','Estoy guardado en el navegador', secure=True, max_age=60*5)
    return respuesta

si queremos borrar la cookie ponemos max_age = 0.

Un ejemplo de como establecer una cookie valida durante 90 días con el atributo expires. 

expires => Debe ser un objeto de datetime o la fecha puesta en formato Unix

Cookie con una duración de 90 días, usando expires y un objeto datetime.

@app.route('/set_cookie90d/')
def save_cookie90d():
    '''Pone una cookie en vigor durante 90 dias'''
    # make_response = La respuesta será 
    respuesta=make_response('Hemos guardado la cookie')
    # en respuesta ira la cookie 'nombre' 'la cookie en si'
    # expire = es un objeto de datetime().
    final = datetime.datetime.now()
    final = final + datetime.timedelta(days=90)
    respuesta.set_cookie('galleta','Estoy guardado en el navegador', secure=True, expires=final)
    return respuesta


Las Cookies están limitadas al directorio. El atributo path.


Si establecemos una cookie con el atributo path, esta queda asociada a esa determinada ruta. Una cookie con un atributo de ruta determinado no se puede enviar a una ruta con la que no esta relacionada, incluso si ambas rutas conviven en el mismo dominio.

Cuando se omite el atributo path durante la creación de la ruta, esta se aplica a todo el dominio "/".

Por ejemplo el código:

respuesta.set_cookie('galleta','Estoy guardado en el navegador', secure=True, 
    path="/get_cookie/")

hace que la cookie quede asociada a esa ruta y no se pueda leer desde ninguna otra.

También las cookies están asignadas a un determinado dominio salvo que se especifique otra cosa con el atributo domain.


¡No toques mi cookie! El atributo HttpOnly.


El atributo HttpOnly al establecer una cookie garantiza que un código escrito en JavaScript no pueda acceder a las cookies. Esta es la forma mas importante de protección contra ataques XSS

Para marcar una cookie como HttpOnly en flask usaremos el siguiente  atributo:

respuesta.set_cookie(key="<nombre>", value="<valor>", httponly=True)


Una cookie marcada como httponly no puede ser accedida desde JavaScript: si utilizamos el inspector de consola del navegador, en documento.cookie aparecerá una cadena de texto vacía.

¿Cuando usar HttpOnly? Pues siempre que puedas. Las cookies deben ser httponly, a menos que tengas un buen motivo para que ser tenga que acceder a ellas usando Javascript en tiempo de ejecución.









No hay comentarios:

Publicar un comentario