Персональный сайт Александра Литовченко

номер32
Поиграть в преферанс в онлайне
3 мая 2008 15:13

Смена session key в django на лету

Если вдруг вам когда-либо понадобится самому задать ключ стандартной django сесcии (например, для синхронизации таблицы сессий при удаленной аутентификации с другим django сайтом), то текущий trunk, к сожалению, не даст этого сделать «в лоб». Обойти это ограничение достаточно просто.

Все дело в том, что в django/contrib/sessions/backends/db.py метод load() у класса SessionStore выглядит так:

def load(self):
    try:
        s = Session.objects.get(
            session_key = self.session_key,
            expire_date__gt=datetime.datetime.now()
        )
        return self.decode(s.session_data)
    except (Session.DoesNotExist, SuspiciousOperation):
        # Create a new session_key for extra security.
        self.session_key = self._get_new_session_key()
        self._session_cache = {}
        # Save immediately to minimize collision
        self.save()
        # Ensure the user is notified via a new cookie.
        self.modified = True
        return {}

То есть при отсутствии записи в базе, новый рандомный session_key генерируется при любых условиях.

Monkey Patching (не говоря уже об изменении исходников самого django) отметем сразу как плохое решение. Но ничего не мешает отнаследоваться от db.SessionStore и подставить в settings.py свой SESSION_ENGINE. Перекрываем load():

from django.conf import settings
from django.contrib.sessions.models import Session
from django.contrib.sessions.backends.db \
    import SessionStore as SessionOldStore
from django.core.exceptions import SuspiciousOperation
import datetime

class SessionStore(SessionOldStore):
    def load(self):
        try:
            s = Session.objects.get(
                session_key = self.session_key, 
                expire_date__gt=datetime.datetime.now()
            )
            return self.decode(s.session_data)
        except (Session.DoesNotExist, SuspiciousOperation):
            # Create a new session_key for extra security.
            if self._session_key is None:
                self.session_key = self._get_new_session_key()
            self._session_cache = {}
            self.save()
            return {}

И теперь, в своих views мы можем свободно устанавливать произвольный session key:

del request.session
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
request.session = engine.SessionStore("MY_SESSION_KEY!")
request.session[SESSION_KEY] = ...

Конечно не стоит забывать, что при таком ручном управлении нам нужно самим следить за уникальностью и «неугадываемостью» ключа.

Комментарии

1 4 мая 2008 13:06, Дима Догадайло

monkey patching часто дает наилучшее решение, например, добавление полей в стандартную django модель User я считаю значительно более удобным, чем использование профайлов или собственных моделей. Поэтому я бы не стал заранее называть monkey patching плохим решением, часто это единственно возможное решение.

С почином, пиши чаще!

2 4 мая 2008 14:11, avl

Вот как раз насчет добавления полей в стандартную модель User при помощи monkey patching я резко против.
Профилей, относящихся к разным приложениям в рамках одного проекта, может быть много. Форуму нужен свой профиль, биллинговой системе — свой, фотогалерее — свой и т. д. И далеко не всегда все эти данные нужны одновременно. Прозрачную работу с профилями прекрасно решает небезызвестный AutoOneToOneField, а при правильном проектировании особых проблем с производительностью не возникает.

3 15 мая 2008 04:12, KOHb

Все так жгут, что я просто вообще не угадываю - но я тоже отмечусь ;)
Сайт - высший.
Саша, пеши есчо!

4 15 мая 2008 04:12, KOHb

Каменты в премодерацию уходят, что ли? Надо бы юзеру об этом как-то сообщать, бо непонятно.

5 15 мая 2008 15:10, avl

Да. В премодерацию. Но парятся там обычно недолго. Сверху поста есть счетчик "Очередь на модерацию: "

6 29 декабря 2009 01:11, Евгений

А вы не подскажите как получить список всех не истекших сессий?

7 29 декабря 2009 14:01, avl

> А вы не подскажите как получить список всех не истекших сессий?
А в чем проблема? Что-то вроде этого.

from datetime import datetime
from django.contrib.session.models import Session

Session.objects.filter(expire_date__lt=datetime.now())

Добавить комментарий

только текст. HTML теги вырезаются:

Пожалуйста будьте вежливы при общении