Как использовать сеансы¶
Django обеспечивает полную поддержку анонимных сессий. Фреймворк сессий позволяет хранить и извлекать произвольные данные для каждого посетителя сайта. Он хранит данные на стороне сервера и абстрагирует отправку и получение cookies. Cookies содержат идентификатор сессии, а не сами данные (если только вы не используете cookie based backend).
Разрешение сеансов¶
Сессии реализуются через кусок middleware.
Чтобы включить функцию сеанса, сделайте следующее:
- Отредактируйте параметр
MIDDLEWARE
и убедитесь, что он содержит'django.contrib.sessions.middleware.SessionMiddleware'
. По умолчаниюsettings.py
, созданныйdjango-admin startproject
, активированSessionMiddleware
.
Если вы не хотите использовать сессии, вы также можете удалить строку SessionMiddleware
из MIDDLEWARE
и 'django.contrib.sessions'
из INSTALLED_APPS
. Это сэкономит вам немного накладных расходов.
Настройка механизма сеансов¶
По умолчанию Django хранит сессии в вашей базе данных (используя модель django.contrib.sessions.models.Session
). Хотя это удобно, в некоторых случаях быстрее хранить данные сессии в другом месте, поэтому Django может быть настроен на хранение данных сессии в вашей файловой системе или в вашем кэше.
Использование сеансов с поддержкой базы данных¶
Если вы хотите использовать сессию с опорой на базу данных, вам нужно добавить 'django.contrib.sessions'
к настройке INSTALLED_APPS
.
После настройки установки выполните команду manage.py migrate
для установки единственной таблицы базы данных, в которой хранятся данные сеанса.
Использование кэшированных сессий¶
Для повышения производительности вы можете использовать бэкэнд сессий на основе кэша.
Чтобы хранить данные сессии, используя систему кэширования Django, вам сначала нужно убедиться, что вы настроили свой кэш; подробности см. в cache documentation.
Предупреждение
You should only use cache-based sessions if you’re using the Memcached or Redis cache backend. The local-memory cache backend doesn’t retain data long enough to be a good choice, and it’ll be faster to use file or database sessions directly instead of sending everything through the file or database cache backends. Additionally, the local-memory cache backend is NOT multi-process safe, therefore probably not a good choice for production environments.
Если у вас несколько кэшей, определенных в CACHES
, Django будет использовать кэш по умолчанию. Чтобы использовать другой кэш, задайте в SESSION_CACHE_ALIAS
имя этого кэша.
Once your cache is configured, you have to choose between a database-backed cache or a non-persistent cache.
Бэкэнд базы данных с кэшем (cached_db
) использует сквозной кэш - записи сессий применяются как к кэшу, так и к базе данных. Сессионные чтения используют кэш или базу данных, если данные были удалены из кэша. Чтобы использовать этот бэкэнд, установите SESSION_ENGINE
в "django.contrib.sessions.backends.cached_db"
и следуйте инструкциям по настройке using database-backed sessions.
Бэкэнд кэша (cache
) хранит данные сессии только в вашем кэше. Это быстрее, поскольку позволяет избежать персистентности базы данных, но вам придется подумать о том, что произойдет, когда данные кэша будут вытеснены. Выселение может произойти, если кэш заполнится или сервер кэша будет перезапущен, и это будет означать потерю данных сессии, включая выход пользователей из системы. Чтобы использовать этот бэкенд, установите SESSION_ENGINE
в "django.contrib.sessions.backends.cache"
.
Бэкэнд кэша можно сделать постоянным, используя постоянный кэш, например, Redis с соответствующей конфигурацией. Но если ваш кэш не настроен на достаточную стойкость, выбирайте бэкэнд базы данных с кэшем. Это позволит избежать побочных ситуаций, вызванных ненадежным хранением данных в производстве.
Использование сеансов на основе файлов¶
Чтобы использовать сессии на основе файлов, установите параметр SESSION_ENGINE
в значение "django.contrib.sessions.backends.file"
.
You might also want to set the SESSION_FILE_PATH
setting (which
defaults to output from tempfile.gettempdir()
, most likely /tmp
) to
control where Django stores session files. Be sure to check that your web
server has permissions to read and write to this location.
Использование сеансов на основе cookie¶
Чтобы использовать сессии на основе cookies, установите параметр SESSION_ENGINE
в значение "django.contrib.sessions.backends.signed_cookies"
. Данные сессии будут храниться с помощью инструментов Django для cryptographic signing и настройки SECRET_KEY
.
Примечание
Рекомендуется оставить настройку SESSION_COOKIE_HTTPONLY
на True
, чтобы предотвратить доступ к хранимым данным из JavaScript.
Предупреждение
If the SECRET_KEY
or SECRET_KEY_FALLBACKS
are not kept
secret and you are using the
django.contrib.sessions.serializers.PickleSerializer
, this can lead
to arbitrary remote code execution.
An attacker in possession of the SECRET_KEY
or
SECRET_KEY_FALLBACKS
can not only generate falsified session
data, which your site will trust, but also remotely execute arbitrary code,
as the data is serialized using pickle.
Если вы используете сеансы на основе cookie, обратите особое внимание на то, чтобы ваш секретный ключ всегда хранился в полном секрете для любой системы, которая может быть удаленно доступна.
Данные сессии подписаны, но не зашифрованы.
При использовании бэкенда cookies данные сессии могут быть прочитаны клиентом.
MAC (Message Authentication Code) используется для защиты данных от изменений со стороны клиента, так что данные сессии будут признаны недействительными при подделке. Такая же недействительность произойдет, если клиент, хранящий cookie (например, браузер вашего пользователя), не сможет сохранить все данные сессионного cookie и сбросит их. Несмотря на то, что Django сжимает данные, все еще вполне возможно превысить common limit of 4096 bytes на одну куку.
Нет гарантии свежести
Обратите также внимание, что хотя MAC может гарантировать подлинность данных (что они были сгенерированы вашим сайтом, а не кем-то другим) и целостность данных (что они все на месте и корректны), он не может гарантировать свежесть, т.е. то, что вам возвращается последнее, что вы отправили клиенту. Это означает, что для некоторых случаев использования данных сеанса бэкенд cookie может открыть вам путь к replay attacks. В отличие от других бэкендов сессий, которые хранят запись каждой сессии на стороне сервера и аннулируют ее, когда пользователь выходит из системы, сессии на основе cookie не аннулируются, когда пользователь выходит из системы. Таким образом, если злоумышленник украдет cookie пользователя, он сможет использовать его для входа в систему под именем этого пользователя, даже если тот выйдет из системы. Cookies будут определяться как «несвежие» только в том случае, если они старше вашего SESSION_COOKIE_AGE
.
Производительность
Finally, the size of a cookie can have an impact on the speed of your site.
Использование сессий в представлениях¶
Когда SessionMiddleware
активирован, каждый объект HttpRequest
- первый аргумент любой функции представления Django - будет иметь атрибут session
, который является словареподобным объектом.
Вы можете читать его и записывать в request.session
в любой точке вашего представления. Вы можете редактировать его несколько раз.
-
class
backends.base.
SessionBase
¶ Это базовый класс для всех объектов сессии. Он имеет следующие стандартные методы словаря:
-
__getitem__
(key)¶ Пример:
fav_color = request.session['fav_color']
-
__setitem__
(key, value)¶ Пример:
request.session['fav_color'] = 'blue'
-
__delitem__
(key)¶ Пример:
del request.session['fav_color']
. Это поднимаетKeyError
, если данныйkey
еще не находится в сессии.
-
__contains__
(key)¶ Пример:
'fav_color' in request.session
-
get
(key, default=None)¶ Пример:
fav_color = request.session.get('fav_color', 'red')
-
pop
(key, default=__not_given)¶ Пример:
fav_color = request.session.pop('fav_color', 'blue')
-
keys
()¶
-
items
()¶
-
setdefault
()¶
-
clear
()¶
Он также имеет такие методы:
-
flush
()¶ Удаляет данные текущей сессии и удаляет куки сессии. Это используется, если вы хотите, чтобы данные предыдущей сессии не могли быть снова доступны из браузера пользователя (например, функция
django.contrib.auth.logout()
вызывает ее).
-
set_test_cookie
()¶ Устанавливает тестовый файл cookie, чтобы определить, поддерживает ли браузер пользователя файлы cookie. В связи с тем, как работают куки, вы не сможете проверить это до следующего запроса страницы пользователем. Дополнительную информацию см. в разделе Setting test cookies ниже.
-
test_cookie_worked
()¶ Возвращает либо
True
, либоFalse
, в зависимости от того, принял ли браузер пользователя тестовый файл cookie. В связи с тем, как работают куки, вам придется вызватьset_test_cookie()
на предыдущем, отдельном запросе страницы. См. раздел Setting test cookies ниже для получения дополнительной информации.
-
delete_test_cookie
()¶ Удаляет тестовый файл cookie. Используйте это, чтобы убрать за собой.
-
get_session_cookie_age
()¶ Возвращает значение параметра
SESSION_COOKIE_AGE
. Это значение может быть переопределено в пользовательском бэкенде сессии.
-
set_expiry
(value)¶ Устанавливает время истечения срока действия сессии. Вы можете передать несколько различных значений:
- Если
value
- целое число, то сессия завершится через столько-то секунд бездействия. Например, вызовrequest.session.set_expiry(300)
приведет к тому, что сессия завершится через 5 минут. - Если
value
является объектомdatetime
илиtimedelta
, то сессия истечет в определенную дату/время. - If
value
is0
, the user’s session cookie will expire when the user’s web browser is closed. - Если
value
равноNone
, сессия возвращается к использованию глобальной политики истечения срока действия сессии.
Чтение сессии не считается активностью для целей истечения срока действия. Срок действия сессии отсчитывается от последнего времени, когда сессия была изменена.
- Если
-
get_expiry_age
()¶ Возвращает количество секунд до истечения срока действия данной сессии. Для сессий без пользовательского срока действия (или настроенных на истечение при закрытии браузера) это значение будет равно
SESSION_COOKIE_AGE
.Эта функция принимает два необязательных аргумента в виде ключевых слов:
modification
: последняя модификация сессии, как объектdatetime
. По умолчанию - текущее время.expiry
: информация об истечении срока действия сессии, в виде объектаdatetime
,int
(в секундах) илиNone
. По умолчанию используется значение, сохраненное в сессии поset_expiry()
, если оно есть, илиNone
.
Примечание
Этот метод используется бэкендами сессий для определения срока действия сессии в секундах при сохранении сессии. Он не предназначен для использования вне этого контекста.
В частности, хотя возможно определить оставшееся время жизни сессии только тогда, когда у вас есть правильное значение
modification
**иexpiry
установлен как объектdatetime
, когда у вас есть значениеmodification
, более просто рассчитать срок действия вручную:expires_at = modification + timedelta(seconds=settings.SESSION_COOKIE_AGE)
-
get_expiry_date
()¶ Возвращает дату истечения срока действия этой сессии. Для сессий без пользовательского срока действия (или настроенных на истечение срока действия при закрытии браузера) эта дата будет равна
SESSION_COOKIE_AGE
секунд от настоящего момента.This function accepts the same keyword arguments as
get_expiry_age()
, and similar notes on usage apply.
-
get_expire_at_browser_close
()¶ Returns either
True
orFalse
, depending on whether the user’s session cookie will expire when the user’s web browser is closed.
-
clear_expired
()¶ Удаляет истекшие сессии из хранилища сессий. Этот метод класса вызывается командой
clearsessions
.
-
cycle_key
()¶ Создает новый ключ сессии, сохраняя текущие данные сессии.
django.contrib.auth.login()
вызывает этот метод для защиты от фиксации сеанса.
-
Сериализация сеанса¶
По умолчанию Django сериализует данные сессии, используя JSON. Вы можете использовать параметр SESSION_SERIALIZER
для настройки формата сериализации сессии. Даже с учетом предостережений, описанных в Напишите свой собственный сериализатор, мы настоятельно рекомендуем придерживаться сериализации JSON особенно если вы используете бэкенд cookie.
For example, here’s an attack scenario if you use pickle
to serialize
session data. If you’re using the signed cookie session backend and SECRET_KEY
(or any key of
SECRET_KEY_FALLBACKS
) is known by an attacker (there isn’t an
inherent vulnerability in Django that would cause it to leak), the attacker
could insert a string into their session which, when unpickled, executes
arbitrary code on the server. The technique for doing so is simple and easily
available on the internet. Although the cookie session storage signs the
cookie-stored data to prevent tampering, a SECRET_KEY
leak
immediately escalates to a remote code execution vulnerability.
Сериализаторы в комплекте¶
-
class
serializers.
JSONSerializer
¶ Обертка вокруг сериализатора JSON из
django.core.signing
. Может сериализовать только основные типы данных.Кроме того, поскольку JSON поддерживает только строковые ключи, обратите внимание, что использование нестроковых ключей в
request.session
не будет работать так, как ожидалось:>>> # initial assignment >>> request.session[0] = 'bar' >>> # subsequent requests following serialization & deserialization >>> # of session data >>> request.session[0] # KeyError >>> request.session['0'] 'bar'
Аналогично, данные, которые не могут быть закодированы в JSON, такие как байты, не относящиеся к стандарту UTF8, например
'\xd9'
(который поднимаетUnicodeDecodeError
), не могут быть сохранены.Более подробно об ограничениях сериализации JSON смотрите в разделе Напишите свой собственный сериализатор.
-
class
serializers.
PickleSerializer
¶ Supports arbitrary Python objects, but, as described above, can lead to a remote code execution vulnerability if
SECRET_KEY
or any key ofSECRET_KEY_FALLBACKS
becomes known by an attacker.Не рекомендуется, начиная с версии 4.1: Из-за риска удаленного выполнения кода этот сериализатор устарел и будет удален в Django 5.0.
Напишите свой собственный сериализатор¶
Note that the JSONSerializer
cannot handle arbitrary Python data types. As is often the case, there is a
trade-off between convenience and security. If you wish to store more advanced
data types including datetime
and Decimal
in JSON backed sessions, you
will need to write a custom serializer (or convert such values to a JSON
serializable object before storing them in request.session
). While
serializing these values is often straightforward
(DjangoJSONEncoder
may be helpful),
writing a decoder that can reliably get back the same thing that you put in is
more fragile. For example, you run the risk of returning a datetime
that
was actually a string that just happened to be in the same format chosen for
datetime
s).
Ваш класс сериализатора должен реализовать два метода, dumps(self, obj)
и loads(self, data)
, для сериализации и десериализации словаря данных сессии, соответственно.
Рекомендации по объектам сеанса¶
- Используйте обычные строки Python в качестве ключей словаря на
request.session
. Это скорее условность, чем жесткое правило. - Ключи словаря сессий, начинающиеся с символа подчеркивания, зарезервированы для внутреннего использования Django.
- Не переопределяйте
request.session
с новым объектом, не обращайтесь к его атрибутам и не устанавливайте их. Используйте его как словарь Python.
Примеры:¶
Это упрощенное представление устанавливает переменную has_commented
в True
после того, как пользователь публикует комментарий. Оно не позволяет пользователю публиковать комментарий более одного раза:
def post_comment(request, new_comment):
if request.session.get('has_commented', False):
return HttpResponse("You've already commented.")
c = comments.Comment(comment=new_comment)
c.save()
request.session['has_commented'] = True
return HttpResponse('Thanks for your comment!')
Это упрощенное представление регистрирует «члена» сайта:
def login(request):
m = Member.objects.get(username=request.POST['username'])
if m.check_password(request.POST['password']):
request.session['member_id'] = m.id
return HttpResponse("You're logged in.")
else:
return HttpResponse("Your username and password didn't match.")
…А этот выводит пользователя из системы, согласно login()
выше:
def logout(request):
try:
del request.session['member_id']
except KeyError:
pass
return HttpResponse("You're logged out.")
Стандартная функция django.contrib.auth.logout()
на самом деле делает немного больше, чем это, чтобы предотвратить непреднамеренную утечку данных. Она вызывает метод flush()
из request.session
. Мы используем этот пример как демонстрацию работы с объектами сессии, а не как полную реализацию logout()
.
Установка тестовых файлов cookie¶
В качестве удобства Django предоставляет способ проверить, принимает ли браузер пользователя cookies. Вызовите метод set_test_cookie()
из request.session
в представлении и вызовите test_cookie_worked()
в последующем представлении - не в том же вызове представления.
Это неудобное разделение между set_test_cookie()
и test_cookie_worked()
необходимо из-за того, как работают куки. Когда вы устанавливаете cookie, вы не можете сказать, принял ли его браузер, до следующего запроса браузера.
Хорошей практикой является использование delete_test_cookie()
, чтобы убрать за собой. Сделайте это после того, как убедитесь, что тестовая печенька сработала.
Вот типичный пример использования:
from django.http import HttpResponse
from django.shortcuts import render
def login(request):
if request.method == 'POST':
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponse("You're logged in.")
else:
return HttpResponse("Please enable cookies and try again.")
request.session.set_test_cookie()
return render(request, 'foo/login_form.html')
Использование сеансов из представлений¶
Примечание
Примеры в этом разделе импортируют объект SessionStore
непосредственно из бэкенда django.contrib.sessions.backends.db
. В своем собственном коде вы должны рассмотреть возможность импорта SessionStore
из механизма сессии, обозначенного SESSION_ENGINE
, как показано ниже:
>>> from importlib import import_module
>>> from django.conf import settings
>>> SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
Для работы с данными сессии вне представления существует API:
>>> from django.contrib.sessions.backends.db import SessionStore
>>> s = SessionStore()
>>> # stored as seconds since epoch since datetimes are not serializable in JSON.
>>> s['last_login'] = 1376587691
>>> s.create()
>>> s.session_key
'2b1189a188b44ad18c35e113ac6ceead'
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
>>> s['last_login']
1376587691
SessionStore.create()
предназначен для создания новой сессии (т.е. сессии, не загруженной из хранилища сессий и с session_key=None
). save()
предназначен для сохранения существующей сессии (т.е. сессии, загруженной из хранилища сессий). Вызов save()
на новой сессии также может сработать, но имеет небольшую вероятность генерации session_key
, которая столкнется с существующей сессией. create()
вызывает save()
и зацикливается, пока не будет сгенерирован неиспользуемый session_key
.
If you’re using the django.contrib.sessions.backends.db
backend, each
session is a normal Django model. The Session
model is defined in
django/contrib/sessions/models.py. Because it’s a normal model, you can
access sessions using the normal Django database API:
>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
>>> s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)
Обратите внимание, что вам нужно будет вызвать get_decoded()
, чтобы получить словарь сессии. Это необходимо, потому что словарь хранится в закодированном формате:
>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}
Когда сохраняются сеансы¶
По умолчанию Django сохраняет данные в базе данных сессии только в том случае, если сессия была изменена - то есть, если любое из значений ее словаря было присвоено или удалено:
# Session is modified.
request.session['foo'] = 'bar'
# Session is modified.
del request.session['foo']
# Session is modified.
request.session['foo'] = {}
# Gotcha: Session is NOT modified, because this alters
# request.session['foo'] instead of request.session.
request.session['foo']['bar'] = 'baz'
В последнем случае приведенного выше примера мы можем явно сообщить объекту сессии, что он был изменен, установив атрибут modified
на объекте сессии:
request.session.modified = True
Чтобы изменить это поведение по умолчанию, установите параметр SESSION_SAVE_EVERY_REQUEST
в значение True
. Если установить значение True
, Django будет сохранять сессию в базе данных при каждом запросе.
Обратите внимание, что сессионный cookie отправляется только тогда, когда сессия была создана или изменена. Если SESSION_SAVE_EVERY_REQUEST
равно True
, сессионный cookie будет отправляться при каждом запросе.
Аналогично, часть expires
сеансового cookie обновляется при каждой отправке сеансового cookie.
Сессия не сохраняется, если код состояния ответа равен 500.
Сеансы длиной в браузер и постоянные сеансы¶
С помощью параметра SESSION_EXPIRE_AT_BROWSER_CLOSE
вы можете контролировать, использует ли фреймворк сессий сеансы длиной в браузер или постоянные сеансы.
По умолчанию значение SESSION_EXPIRE_AT_BROWSER_CLOSE
установлено на False
, что означает, что сеансовые куки будут храниться в браузерах пользователей до тех пор, пока SESSION_COOKIE_AGE
. Используйте это, если вы не хотите, чтобы людям приходилось входить в систему каждый раз, когда они открывают браузер.
Если SESSION_EXPIRE_AT_BROWSER_CLOSE
установлено в значение True
, Django будет использовать cookies длиной в браузер - cookies, срок действия которых истекает, как только пользователь закрывает браузер. Используйте это, если вы хотите, чтобы людям приходилось входить в систему каждый раз, когда они открывают браузер.
Эта настройка является глобальной по умолчанию и может быть перезаписана на уровне каждой сессии путем явного вызова метода set_expiry()
из request.session
, как описано выше в using sessions in views.
Примечание
Some browsers (Chrome, for example) provide settings that allow users to
continue browsing sessions after closing and reopening the browser. In
some cases, this can interfere with the
SESSION_EXPIRE_AT_BROWSER_CLOSE
setting and prevent sessions
from expiring on browser close. Please be aware of this while testing
Django applications which have the
SESSION_EXPIRE_AT_BROWSER_CLOSE
setting enabled.
Очистка хранилища сеансов¶
По мере того как пользователи создают новые сессии на вашем сайте, данные сессии могут накапливаться в хранилище сессий. Если вы используете бэкенд базы данных, таблица базы данных django_session
будет расти. Если вы используете файловый бэкенд, ваш временный каталог будет содержать все большее количество файлов.
Чтобы понять эту проблему, рассмотрим, что происходит с бэкендом базы данных. Когда пользователь входит в систему, Django добавляет строку в таблицу базы данных django_session
. Django обновляет эту строку каждый раз, когда данные сессии изменяются. Если пользователь выходит из системы вручную, Django удаляет эту строку. Но если пользователь не вышел из системы, строка никогда не будет удалена. Аналогичный процесс происходит и с файловым бэкендом.
Django не обеспечивает автоматическую очистку истекших сессий. Поэтому ваша работа заключается в регулярной очистке истекших сессий. Django предоставляет для этого команду управления очисткой: clearsessions
. Рекомендуется вызывать эту команду на регулярной основе, например, в качестве ежедневного задания cron.
Обратите внимание, что бэкэнд кэша не подвержен этой проблеме, поскольку кэш автоматически удаляет устаревшие данные. Бэкэнд cookie также не подвержен этой проблеме, поскольку данные сессии хранятся в браузерах пользователей.
Настройки¶
Несколько Django settings дают вам контроль над поведением сессии:
Безопасность сеанса¶
Поддомены внутри сайта могут устанавливать cookies на клиенте для всего домена. Это делает фиксацию сеанса возможной, если cookies разрешены с поддоменов, не контролируемых доверенными пользователями.
Например, злоумышленник может войти в good.example.com
и получить действительную сессию для своей учетной записи. Если злоумышленник имеет контроль над bad.example.com
, он может использовать его для отправки вам ключа сессии, поскольку поддомену разрешено устанавливать cookies на *.example.com
. Когда вы посетите good.example.com
, вы войдете в систему как злоумышленник и можете случайно ввести свои конфиденциальные личные данные (например, информацию о кредитной карте) в аккаунт злоумышленника.
Другой возможной атакой будет, если good.example.com
установит свой SESSION_COOKIE_DOMAIN
на "example.com"
, что приведет к отправке сессионных cookie с этого сайта на bad.example.com
.
Технические детали¶
- The session dictionary accepts any
json
serializable value when usingJSONSerializer
. - Данные сессии хранятся в таблице базы данных с именем
django_session
. - Django отправляет cookie только в том случае, если это необходимо. Если вы не задаете никаких данных сессии, он не будет отправлять сессионный cookie.
Объект SessionStore
¶
При внутренней работе с сессиями Django использует объект session store из соответствующего движка сессий. По соглашению, класс объекта хранилища сессий называется SessionStore
и находится в модуле, обозначенном SESSION_ENGINE
.
Все классы SessionStore
, доступные в Django, наследуются от SessionBase
и реализуют методы манипулирования данными, а именно:
exists()
create()
save()
delete()
load()
clear_expired()
Для того чтобы создать пользовательский механизм сессий или адаптировать существующий, вы можете создать новый класс, наследующий от SessionBase
или любого другого существующего класса SessionStore
.
Вы можете расширить сеансовые движки, но для этого при использовании сеансовых движков с поддержкой базы данных обычно требуются дополнительные усилия (подробности см. в следующем разделе).
Расширение сеансовых движков с опорой на базу данных¶
Создание собственного механизма сессий с поддержкой базы данных на основе тех, которые включены в Django (а именно db
и cached_db
) может быть сделано путем наследования AbstractBaseSession
и одного из классов SessionStore
.
AbstractBaseSession
и BaseSessionManager
импортируются из django.contrib.sessions.base_session
так, что их можно импортировать, не включая django.contrib.sessions
в INSTALLED_APPS
.
-
class
base_session.
AbstractBaseSession
¶ Абстрактная базовая модель сеанса.
-
session_key
¶ Первичный ключ. Само поле может содержать до 40 символов. Текущая реализация генерирует 32-символьную строку (случайная последовательность цифр и строчных букв ASCII).
-
session_data
¶ Строка, содержащая закодированный и сериализованный словарь сессии.
-
expire_date
¶ Время, обозначающее дату окончания сеанса.
Просроченные сессии недоступны пользователю, однако они могут сохраняться в базе данных до тех пор, пока не будет выполнена команда управления
clearsessions
.
-
classmethod
get_session_store_class
()¶ Возвращает класс хранилища сессии, который будет использоваться с данной моделью сессии.
-
get_decoded
()¶ Возвращает декодированные данные сессии.
Декодирование выполняется классом хранилища сессий.
-
Вы также можете настроить менеджер моделей, создав подкласс BaseSessionManager
:
-
class
base_session.
BaseSessionManager
¶ -
encode
(session_dict)¶ Возвращает заданный словарь сессии, сериализованный и закодированный в виде строки.
Кодирование выполняется классом хранилища сессий, привязанным к классу модели.
-
save
(session_key, session_dict, expire_date)¶ Сохраняет данные сессии для предоставленного ключа сессии или удаляет сессию, если данные пусты.
-
Настройка классов SessionStore
достигается путем переопределения методов и свойств, описанных ниже:
-
class
backends.db.
SessionStore
¶ Реализует хранение сессий с опорой на базу данных.
-
classmethod
get_model_class
()¶ Переопределите этот метод, чтобы вернуть пользовательскую модель сессии, если она вам нужна.
-
create_model_instance
(data)¶ Возвращает новый экземпляр объекта модели сессии, который представляет текущее состояние сессии.
Переопределение этого метода дает возможность изменять данные модели сессии до их сохранения в базе данных.
-
classmethod
-
class
backends.cached_db.
SessionStore
¶ Реализует кэшированное хранилище сессий на основе базы данных.
-
cache_key_prefix
¶ Префикс, добавляемый к ключу сессии для построения строки ключа кэша.
-
Пример¶
В приведенном ниже примере показан пользовательский механизм сессий на основе базы данных, который включает дополнительный столбец базы данных для хранения идентификатора учетной записи (таким образом обеспечивая возможность запроса базы данных для всех активных сессий для учетной записи):
from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.contrib.sessions.base_session import AbstractBaseSession
from django.db import models
class CustomSession(AbstractBaseSession):
account_id = models.IntegerField(null=True, db_index=True)
@classmethod
def get_session_store_class(cls):
return SessionStore
class SessionStore(DBStore):
@classmethod
def get_model_class(cls):
return CustomSession
def create_model_instance(self, data):
obj = super().create_model_instance(data)
try:
account_id = int(data.get('_auth_user_id'))
except (ValueError, TypeError):
account_id = None
obj.account_id = account_id
return obj
Если вы переходите со встроенного в Django хранилища сессий cached_db
на пользовательское, основанное на cached_db
, вам следует переопределить префикс ключа кэша, чтобы предотвратить столкновение пространств имен:
class SessionStore(CachedDBStore):
cache_key_prefix = 'mysessions.custom_cached_db_backend'
# ...
Идентификаторы сессий в URL-адресах¶
Фреймворк сессий Django полностью и исключительно основан на cookie. Он не возвращается к помещению идентификаторов сессий в URL в качестве последнего средства, как это делает PHP. Это намеренное дизайнерское решение. Такое поведение не только делает URL уродливыми, но и делает ваш сайт уязвимым для кражи идентификатора сессии через заголовок «Referer».