Порядок работы с сессиями (session)

На этом занятии мы поближе познакомимся с механизмом сессий, который уже затрагивали, когда говорили о мгновенных сообщениях. Так вот, сессии работают по похожему с cookies принципу: они также хранятся в браузере в виде особых кук сессий, но дополнительно шифруются с помощью ключа, который можно задать в WSGI-приложении, следующим образом:

from flask import Flask, render_template, make_response, url_for, request
 
app = Flask(__name__)
app.config['SECRET_KEY'] = 'cb02820a3e94d72c9f950ee10ef7e3f7a35b3f5b'

Для надежности этот ключ должен содержать самые разные символы и один из хороших способов его сгенерировать – это воспользоваться следующей командой пакета os:

os.urandom(20).hex()

То есть, мы можем ее выполнить, например, в консоли Python и результат вставить в секретный ключ. Соответственно, не зная этот ключ, пользователь не сможет понять и изменить сессионную информацию в браузере. Фактически, только этим сессии и отличаются от cookies, о которых мы говорили на предыдущем занятии. Во всем остальном они практически не отличимы: также передаются в запросах браузеру и обратно – из браузера к серверу. Имеют ограничение в 4 Кб хранимой информации и перестают работать, если пользователь отключит cookies в своем браузере. Но, вместе с тем, почти ни один серьезный сайт без них не обходится.

Объект session

Для работы с сессиями во Flask имеется специальный объект

session

который доступен и в приложении и в шаблонах. Данный объект работает по подобию словаря, следующим образом:

@app.route("/")
def index():
    if 'visits' in session:
        session['visits'] = session.get('visits') + 1  # обновление данных сессии
    else:
        session['visits'] = 1  # запись данных в сессию
 
    return f"<h1>Main Page</h1>Число просмотров: {session['visits']}"

Смотрите, мы здесь обращаемся к данным сессии по ключу 'visits', если они там есть. Иначе, создаем этот ключ со значением 1. Далее, при каждом обновлении страницы значение 'visits' будет увеличиваться на 1 и мы увидим увеличение числа просмотров главной страницы сайта. Это лишь простой пример, демонстрирующий порядок работы с объектом session во Flask. Шифрование, передача и прием данных через запросы скрыта и происходит в автоматическом режиме, что очень удобно.

Но при работе с сессиями есть одна существенная особенность, которую следует знать и хорошо понимать: передача сессионных данных браузеру происходит только при изменении состояния объекта session. Чтобы лучше понять о чем речь, рассмотрим такой отвлеченный, но простой пример:

data = [1,2,3,4]
@app.route("/session")
def session_data():
    if 'data' not in session:
        session['data'] = data
    else:
        session['data'][1] += 1
 
    return f"session['data']: {session['data']}"

Мы здесь при первом запросе формируем поле data, которое ссылается на список data. А при последующих запросах происходит увеличение второго элемента этого списка на 1. По идее, при обновлении страницы, мы должны видеть постоянное увеличение второго значения на 1. Давайте посмотрим, обновляем, но ничего не происходит. Почему? Как раз по той причине, что объект session в этом случае никак не меняется: он как ссылался на список, так и ссылается (адрес списка остается прежним). Меняется лишь элемент в самом списке и это изменение не влияет на изменение session. А раз так, то Flask решает, что сессия не поменялась и нет смысла нагружать канал связи и дополнительно ее отправлять браузеру.

Но это можно поправить, прописав следующую строчку:

session.modified = True

Этим мы явно указываем Flask, что состояние сессии изменилось и ее нужно обновить в браузере. Теперь, при обновлении страницы, второй элемент списка будет увеличиваться каждый раз на единицу.

Время жизни сессии

По умолчанию куки сессии существуют, пока пользователь не закроет браузер. Но это поведение можно изменить и явно указать время жизни сессий в куках. Для этого в функции представления нужно указать:

session.permanent = True

Тогда время жизни сессии устанавливается равным параметру

app.permanent_session_lifetime

который по умолчанию составляет 31 день. Но, можно определить любое другое значение, например, так:

app.permanent_session_lifetime = datetime.timedelta(days=10)

Теперь сессии будут максимум храниться 10 дней в браузере клиента. Давайте посмотрим на работу этого функционала. Если сейчас произвести обновления страницы

127.0.0.1:5000/session

то увидим увеличение второго значения списка. Выйдем из браузера, снова зайдем и увидим последнее установленное значения, т.е. сессия сохраняется в браузере. Далее, изменим значение:

session.permanent = False

также обновим страницу, выйдем из браузера и при возвращении увидим начальные значения списка 1, 2, 3, 4, т.е. сессия пропала при закрытии окна браузера. Вот так это работает.

Видео по теме