Flask Session y Cookie

El protocolo HTTP en sí mismo no tiene estado: el servidor no recuerda automáticamente si dos solicitudes provienen del mismo usuario.

Flask, medianteSessionel mecanismo, resuelve este problema, permitiendo que las aplicaciones web puedan «recordar» el estado del usuario.


Cómo funciona Session

Flask usa de forma predeterminadaSecureCookieSessionsu modo de funcionamiento es:

  • Los datos de Session se serializan, se firman con una clave y se guardan en la Cookie del navegador.
  • En cada solicitud, el navegador envía automáticamente esta Cookie.
  • Flask, después de verificar la firma, restaura los datos a un diccionario de Python para que los uses.

Los usuarios pueden ver el contenido de la Cookie (porque está codificada en base64), pero no pueden modificarla, ya que cualquier cambio provocaría que la verificación de la firma fallara.

Session 签名 Cookie 工作机制


Configurar SECRET_KEY

Para usar Session, primero debes configurarSECRET_KEY—la clave utilizada para firmar.

Ejemplo

import secrets
from flask import Flask

app = Flask(__name__)

# Genera una clave aleatoria segura (solo necesita generarse en la primera ejecución)
# secrets.token_hex() produce una cadena hexadecimal aleatoria de 64 caracteres
app.secret_key = secrets.token_hex()
# O simplemente establece un valor fijo (conveniente para desarrollo, pero no lo uses en producción)
# app.secret_key = "dev-secret-key-change-in-production"

Importante:SECRET_KEYSECRET_KEY debe mantenerse en secreto y ser suficientemente aleatoria. Si la clave se filtra, cualquiera puede falsificar los datos de Session de tu aplicación. En producción, debe leerse desde variables de entorno o archivos de configuración; no la hardcodees en el código.

Comando para generar una clave de alta calidad:

$ python -c 'import secrets; print(secrets.token_hex())'
192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf

Leer y escribir Session

sessionsession es un objeto similar a un diccionario; su uso es básicamente igual al de un diccionario de Python:

Ejemplo

from flask import Flask, session, redirect, url_for, request

app = Flask(__name__)
app.secret_key = "dev-secret-key"

@app.route("/")
def index():
    # Comprueba si hay un username en session
    if "username" in session:
        return f"""
<h1>¡Bienvenido de nuevo, {session["username"]}!</h1>
<p>Tus visitas: {session.get("visits", 0)}</p>
<p><a href="/logout">Cerrar sesión</a></p>
        """


    return """
<h1>Página de inicio de EJEMPLO</h1>
<p>Aún no has iniciado sesión.</p>
<p><a href="/login">Ir a iniciar sesión</a></p>
    """


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form.get("username", "")
        if username:
            # Guarda el nombre de usuario en session
            session["username"] = username
            # Inicializa el contador de visitas
            session["visits"] = 0
            return redirect(url_for("index"))

    return """
    <form method="post">
<h2>Iniciar sesión en EJEMPLO</h2>
<p><input type="text" name="username" placeholder="Introduce tu nombre de usuario"></p>
<p><input type="submit" value="Iniciar sesión"></p>
    </form>
    """


@app.route("/logout")
def logout():
    # Elimina todos los datos de session
    session.clear()
    # O elimina solo una clave específica:
    # session.pop("username", None)
    return redirect(url_for("index"))

Session permanente

De forma predeterminada, Session caduca cuando se cierra el navegador (a nivel de sesión del navegador).

Si necesitas la función «recordarme», puedes marcar Session comopermanente:

Ejemplo

from datetime import timedelta

# Establece la validez de la session permanente (31 días por defecto)
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(days=7)

@app.post("/login-remember")
def login_remember():
    username = request.form.get("username")
    if username:
        session["username"] = username
        # Márcala como session permanente; seguirá siendo válida después de cerrar el navegador
        session.permanent = True
        return redirect(url_for("index"))

Message Flashing: mensajes de una sola vez

Después de que el usuario envía un formulario, es necesario mostrar un mensaje de retroalimentación como «operación exitosa» o «error».

Para este tipo de mensajes que «desaparecen después de mostrarse una vez», Flask proporcionaflash()el mecanismo.

Ejemplo

from flask import Flask, flash, get_flashed_messages, redirect, render_template, request, url_for

app = Flask(__name__)
app.secret_key = "dev-secret-key"

@app.route("/post", methods=["GET", "POST"])
def create_post():
    if request.method == "POST":
        title = request.form.get("title", "").strip()

        if not title:
            # Guarda el mensaje de error en flash, con categoría "error"
            flash("El título no puede estar vacío", "error")
            return redirect(url_for("create_post"))

        # Guarda el mensaje de éxito en flash, con categoría "success"
        flash(f"¡El artículo «{title}» se publicó con éxito!", "success")
        return redirect(url_for("create_post"))

    return render_template("create_post.html")

@app.route("/flash-demo")
def flash_demo():
    # Obtiene todos los mensajes flash (se eliminan automáticamente al leerlos)
    messages = get_flashed_messages(with_categories=True)
    return render_template("flash_demo.html", messages=messages)

Renderizar mensajes flash en la plantilla:

Ejemplo

<!-- Ruta del archivo: templates/create_post.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Publicar artículo - EJEMPLO</title>
    <style>
        .flash-success { color: green; background: #E8EEF5; padding: 10px; border-radius: 4px; }
        .flash-error { color: red; background: #ffebee; padding: 10px; border-radius: 4px; }
        .flash-info { color: blue; background: #e3f2fd; padding: 10px; border-radius: 4px; }
    </style>
</head>
<body>
    <h1>Publicar artículo</h1>

    <!-- Obtener y mostrar todos los mensajes flash -->
    {% with messages = get_flashed_messages(with_categories=true) %}
        {% if messages %}
            {% for category, message in messages %}
                <div class="flash-{{ category }}">{{ message }}</div>
            {% endfor %}
        {% endif %}
    {% endwith %}

    <form method="post">
        <p>Título:<input type="text" name="title" style="width:300px;"></p>
        <p><input type="submit" value="Publicar"></p>
    </form>
</body>
</html>
Categoría Escenarios de uso recomendados
"message" (predeterminado) Notificación general
"success" Operación exitosa
"error" Operación fallida
"warning" Mensaje de advertencia
"info" Información general

Los mensajes Flash dependen de Session, por lo que debes configurarSECRET_KEYpara poder utilizarlos.


Preguntas frecuentes sobre Session

Límite de tamaño de Cookie: el navegador limita el tamaño de una Cookie individual a aproximadamente 4KB. No almacenes grandes cantidades de datos en Session; es adecuada para información ligera como ID de usuario o preferencias, pero no para archivos u objetos grandes.

Otras extensiones