Если принять во внимание все эти ограничения и потенциальные дыры в безопасности, становится очевидно, что cookie и постоянные сессии являются «головной болью» веб разработчиков. Цель Django в данном случае — быть эффективным средством лечения этой боли, таким образом, оно поставляется со средой управления сессиями, которая решает эти задачи за вас.
Среда управления сессиями позволяет вам хранить и получать определённые данные на основе посетителей сайта. Она сохраняет данные на сервере и берёт управление получением и отправлением cookie на себя. Cookie используются только для передачи идентификатора сессии, а не самих данных, это предохраняет вас от большинства проблем с cookie.
Давайте рассмотрим как активируются сессии и как они используются в функциях представлений.
Сессии реализованы с помощью отдельного модуля (см. главу «Компоненты») и моделей Django. Для активации сессий выполните следующие шаги:
Измените параметр MIDDLEWARE_CLASSES, добавив в него значение django.contrib.sessions.middleware.SessionMiddleware.
Внесите в параметр INSTALLED_APPS значение django.contrib.sessions. Запустите manage.py syncdb после этого.
Стандартный шаблон приложения, созданный с помощью startproject уже имеет все необходимые настройки и если вы ничего не удаляли, то ничего добавлять не понадобится для работы сессий.
Если вам не требуется использовать сессии, вы можете удалить строку SessionMiddleware из параметра MIDDLEWARE_CLASSES и строку django.contrib.sessions из параметра INSTALLED_APPS. Это позволит вам освободить крайне незначительную часть ресурсов, но из маленьких частей складываются большие.
После активации SessionMiddleware каждый объект
HttpRequest — первый аргумент любой функции представления Django — будет иметь атрибут
session по функциональности аналогичный
словарю. Пример:
# Установим значение ключа в сессии:
request.session["fav_color"] = "blue"
# Получим значение ключа из сессии -- можно это сделать в
# другом представлении или через несколько запросов
# (или и то и другое):
fav_color = request.session["fav_color"]
# Чистим значение ключа в сессии:
del request.session["fav_color"]
# Проверка наличия ключа в сессии:
if "fav_color" in request.session:
...
Вы также можете использовать другие методы, такие как
keys() и items()
объекта request.session.
Есть ряд простых правил для эффективного использования сессий в Django:
Используйте для объекта
request.sessionобычные строки Python в качестве ключей словаря. Это правило служит больше для удобства, чем для ускорения работы, но оно стоит того, чтобы ему следовать.Словарные ключи сессии, которые начинаются с символа «подчёркивание», зарезервированы для внутреннего использования Django. На практике среда использует небольшой набор зарезервированных переменных в сессии, но пока вы не знаете об их назначении, не стоит их трогать.
Не заменяйте request.session новым объектом и не работайте с его атрибутами. Используйте его как обычный словарь Python.
Рассмотрим несколько примеров. Нижеприведённая простейшая
функция представления устанавливает переменной
has_commented значение True
после того, как пользователь отправляет комментарий. Это
простой (но небезопасный) способ предотвращения повторной
отправки пользовательского комментария:
def post_comment(request, new_comment):
if request.session.get('has_commented', False):
return HttpResponse("Вы уже отправили комментарий")
c = comments.Comment(comment=new_comment)
c.save()
request.session['has_commented'] = True
return HttpResponse('Спасибо за ваш комментарий!')
Это простейшее представление аутентифицирует пользователя на сайте:
def login(request):
try:
m = Member.objects.get(username__exact=request.POST['username'])
if m.password == request.POST['password']:
request.session['member_id'] = m.id
return HttpResponse("Вы авторизованы.")
except Member.DoesNotExist:
return HttpResponse("Ваши логин и пароль не соответствуют.")
Это представление отключает ранее авторизованного пользователя:
def logout(request):
try:
del request.session['member_id']
except KeyError:
pass
return HttpResponse("Вы вышли.")
Замечание
В настоящем проекте так не делают. Применение ранее упомянутой среды аутентификации упрощает решение этой задачи. Эти примеры были умышленно упрощены для облегчения их понимания.
Как было сказано ранее, вы не можете полагаться на то, что
каждый браузер будет принимать cookie. Таким образом, для
удобства, Django предоставляет простой способ проверки
возможности приёма браузером отправляемых вами cookie. Вам
просто следует вызвать в представлении метод
request.session.set_test_cookie() и
проверить в последующем представлении (не в том же самом), что
возвращает метод
request.session.test_cookie_worked().
Это неудобное разделение вызовов методом является необходимым из-за особенностей функционирования cookie. Когда вы устанавливаете cookie, вы не можете проверить, принял ли браузер cookie или нет. Для проверки требуется сделать дополнительный запрос.
Хорошим тоном является уборка за собой с помощью метода
delete_test_cookie(). Выполните уборку
после завершения проверки механизма cookie.
Ниже приведён пример обычного использования этого механизма:
def login(request):
# Если мы отправили форму...
if request.method == 'POST':
# Проверить, что браузер принимает cookie:
if request.session.test_cookie_worked():
# Браузер принимает, удаляем тестовый cookie.
request.session.delete_test_cookie()
# На практике нам потребуется некая логика для проверки
# логина и пароля, но так как это всего лишь пример...
return HttpResponse("You're logged in.")
# Проверка не прошла, отображаем сообщение об ошибке.
# На настоящем сайте нам потребуется отображать это покрасивее.
else:
return HttpResponse("Please enable cookies and try again.")
# Если мы не отсылали форму, отправляем тестовое cookie
# вместе с формой аутентификации.
request.session.set_test_cookie()
return render_to_response('foo/login_form.html')
Замечание
И снова, встроенные функции аутентификации выполнят эту проверку за вас.
С точки зрения реализации, каждая сессия является обычной моделью Django, определённой в django.contrib.sessions.models. Каждая сессия идентифицировануется 32-символьным хэшем, который сохраняется в cookie. Раз это обычная модель, вы можете получать доступ к сессиям с помощью стандартного 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 сохраняет информацию в базе данных только когда в сессию были внесены изменения, т.е. когда были изменены или удалены значения словаря сессии:
# Сессия изменена.
request.session['foo'] = 'bar'
# Сессия изменена.
del request.session['foo']
# Сессия изменена.
request.session['foo'] = {}
# Фишка: Сессия НЕ изменена, так как производится изменение
# request.session['foo'], а не request.session.
request.session['foo']['bar'] = 'baz'
Для изменения этого поведения надо назначить параметру SESSION_SAVE_EVERY_REQUEST значение True. В этом случае Django будет сохранять сессию в базе данных на каждый запрос, даже если не было никаких изменений.
Следует отметить, что cookie сессии отправляется только в случае, когда сессия была создана или изменена. Если параметр SESSION_SAVE_EVERY_REQUEST имеет значение True, cookie сессии будет отправляться при каждом запросе. Аналогично, элемент сессии expires обновляется каждый раз при отправке cookie.
Вы могли отметить, что cookie, которую нам прислал Google содержала expires=Sun, 17-Jan-2038 19:14:07 GMT;. Cookie могут по необходимости содержать дату окончания своей деятельности, которая указывает браузеру, когда надо удалить эту cookie. Если cookie не содержит такой элемент, браузер удалит её после того, как пользователь закроет его. Вы можете контролировать поведение среды управления сессиями с помощью параметра SESSION_EXPIRE_AT_BROWSER_CLOSE.
По умолчанию параметр SESSION_EXPIRE_AT_BROWSER_CLOSE имеет значение False, которое означает, что cookie сессий будут сохраняться в пользовательском браузере на SESSION_COOKIE_AGE секунд (изначально это значение равно двум неделям или 1'209'600 секунд). Используйте эту возможность, если не требуется постоянно заставлять людей аутентифицироваться при каждом открытии браузера.
Если параметр SESSION_EXPIRE_AT_BROWSER_CLOSE имеет значение True, Django будет использовать cookie, которые будут «жить» пока пользователь не закроет браузер.
Кроме уже рассмотренных параметров есть ещё несколько, которые влияют на то как Django работает с сессиями, используя cookie. Они показаны в таблице «Параметры, влияющие на поведение cookie»:
Таблица 12.2. Параметры, влияющие на поведение cookie
| Параметр | По умолчанию | Описание |
|---|---|---|
| SESSION_COOKIE_DOMAIN | None | Домен для которого предназначено cookie. Строковое значение, подобное «.lawrence.com» для кроссдоменных cookie или используйте None для текущего домена. |
| SESSION_COOKIE_NAME | sessionid | Имя для cookie используемого для сессии. Может быть любой строкой. |
| SESSION_COOKIE_SECURE | False | Определяет надо ли использовать «защищённые» cookie для сессии. Если значение этого параметра установлено в True, cookie будет помечено как «защищённое» и браузеры будут передавать его только по HTTPS. |
Техническая информация
Для любопытных читателей здесь приведена техническая информация по особенностям работы среды управления сессиями:
Словарь сессии принимает любой объект Python, который может быть сериализован с помощью модуля pickle. За подробностями обратитесь к документации на язык Python к модулю pickle.
Данные сессии хранятся в таблице django_session базы данных.
Данные сессии доступны по требованию. Если вы никогда не обращаетесь к request.session, Django не будет обращаться к этой таблице в базе данных.
Django передаёт cookie только когда это надо. Если вы не назначили данные для сессии, Django не будет передавать cookie для сессии (если только вы не активировали SESSION_SAVE_EVERY_REQUEST).
Среда управления сессиями основана на использовании cookie. Она не будет пытаться размещать идентификатор сессии в URL, как это делают PHP или JSP, в случае когда пользователь отключил поддержку cookie.
Такое поведение определено дизайном Django. Размещение идентификатора сессии в URL не только уродует последний, но и также делает ваш сайт беззащитным к определённым формам кражи идентификатора через заголовок Referrer.
Если мы ещё не убили в вас любопытство, дальнейшие шаги очевидны. Загляните в django.contrib.sessions, там много интересного.
| Пред. | Уровень выше | След. |
| Глава 12. Сессии, пользователи и регистрация | Начало | Аутентификация пользователей |
0 comments | Make a comment