Сессия и Cookie во Flask

Сам протокол HTTP не имеет состояния — сервер не будет автоматически запоминать, приходят ли два запроса от одного и того же пользователя.

Flask с помощьюсессий— этот механизм решает эту проблему, позволяя веб-приложениям "запоминать" состояние пользователя.


Как работает Session

Flask по умолчанию используетSecureCookieSession, и принцип его работы таков:

  • Данные Session сериализуются, подписываются ключом и сохраняются в Cookie браузера.
  • При каждом запросе браузер автоматически передаёт этот Cookie.
  • После проверки подписи Flask восстанавливает данные в словарь Python, который вы можете использовать.

Пользователи могут видеть содержимое Cookie (поскольку оно закодировано в base64), но не могут его подделать — потому что любое изменение приведёт к сбою проверки подписи.

Session 签名 Cookie 工作机制


Настройка SECRET_KEY

Чтобы использовать Session, сначала нужно задать секретный ключ.SECRET_KEY— секретный ключ, используемый для подписи.

Пример

import secrets
from flask import Flask

app = Flask(__name__)

# Сгенерируйте безопасный случайный ключ (нужно сгенерировать только при первом запуске)
# secrets.token_hex() создаёт 64-символьную шестнадцатеричную случайную строку
app.secret_key = secrets.token_hex()
# Или напрямую задайте фиксированное значение (удобно для разработки, но не используйте его в продакшене)
# app.secret_key = "dev-secret-key-change-in-production"

Важно:SECRET_KEYЕго необходимо держать в секрете, и он должен быть достаточно случайным. Если ключ утечёт, любой сможет подделать данные сессии вашего приложения. В продакшене читайте его из переменных окружения или файлов конфигурации — не прописывайте его жёстко в коде.

Команда для генерации высококачественного ключа:

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

Чтение и запись сессии

sessionЭто объект, подобный словарю, используется в основном так же, как словарь Python:

Пример

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

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

@app.route("/")
def index():
    # Проверить, содержит ли session username
    if "username" in session:
        return f"""
<h1>С возвращением, {session["username"]}!</h1>
<p>Ваше количество посещений: {session.get("visits", 0)}</p>
<p><a href="/logout">Выйти</a></p>
        """


    return """
<h1>ПРИМЕР Домашняя страница</h1>
<p>Вы ещё не вошли в систему.</p>
<p><a href="/login">Перейти к входу</a></p>
    """


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form.get("username", "")
        if username:
            # Сохранить имя пользователя в сессии
            session["username"] = username
            # Инициализировать счётчик посещений
            session["visits"] = 0
            return redirect(url_for("index"))

    return """
    <form method="post">
<h2>Войти в EXAMPLE</h2>
<p><input type="text" name="username" placeholder="Введите имя пользователя"></p>
<p><input type="submit" value="Войти"></p>
    </form>
    """


@app.route("/logout")
def logout():
    # Очистить все данные в сессии
    session.clear()
    # Или удалить только конкретный ключ:
    # session.pop("username", None)
    return redirect(url_for("index"))

Постоянная сессия

По умолчанию сессия становится недействительной после закрытия браузера (на уровне сессии браузера).

Если вам нужна функция "Запомнить меня", вы можете пометить сессию как постоянную.Постоянная (permanent):

Пример

from datetime import timedelta

# Установить срок действия постоянной сессии (по умолчанию 31 день)
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
        # Пометить сессию как постоянную, она остаётся действительной после закрытия браузера
        session.permanent = True
        return redirect(url_for("index"))

Flash-сообщения——одноразовые сообщения

После того как пользователь отправит форму, необходимо отобразить сообщения обратной связи, например "Операция выполнена успешно" или "Ошибка".

Для таких сообщений, которые "исчезают после однократного отображения", Flask предоставляет flash-сообщения.flash()Механизм.

Пример

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:
            # Сохранить сообщение об ошибке в flash, с категорией "error"
            flash("Заголовок не может быть пустым", "error")
            return redirect(url_for("create_post"))

        # Сохранить сообщение об успехе в flash, с категорией "success"
        flash(f"Статья '{title}' успешно опубликована!", "success")
        return redirect(url_for("create_post"))

    return render_template("create_post.html")

@app.route("/flash-demo")
def flash_demo():
    # Получить все flash-сообщения (автоматически очищаются после чтения)
    messages = get_flashed_messages(with_categories=True)
    return render_template("flash_demo.html", messages=messages)

Отображение flash-сообщений в шаблонах:

Пример

<!-- Путь к файлу: templates/create_post.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Опубликовать статью - EXAMPLE</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>Опубликовать статью</h1>

    <!-- Получить и отобразить все 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>Заголовок:<input type="text" name="title" style="width:300px;"></p>
        <p><input type="submit" value="Опубликовать"></p>
    </форма>
</body>
</html>
Категория Рекомендуемые сценарии использования
"message" (по умолчанию) Общее уведомление
"success" Операция выполнена успешно
"error" Операция не удалась
"warning" Предупреждающее сообщение
"info" Общая информация

Flash-сообщения зависят от Session, поэтому необходимо задать секретный ключ.SECRET_KEYТолько тогда его можно использовать.


Вопросы и ответы по Session

Ограничение размера CookieПримечание: Браузеры ограничивают размер одного Cookie примерно 4KB. Не храните большие объёмы данных в Session — он подходит для лёгкой информации, такой как идентификаторы пользователей и настройки, а не для файлов или больших объектов.

Другие расширения