Как найти сессию Django для конкретного пользователя? - PullRequest
50 голосов
/ 25 октября 2008

Я пишу приложение, в котором я буду получать доступ к базе данных из django и из отдельного приложения. Оба должны выполнить проверку сеанса, и сеанс должен быть одинаковым для них обоих. Django имеет встроенную аутентификацию / проверку сеанса, и это то, что я использую, теперь мне нужно выяснить, как повторно использовать тот же сеанс для моего отдельного приложения.

У меня вопрос, как я могу найти ключ сеанса для конкретного пользователя?

Из того, что он выглядит, нет ничего, что связывало бы auth_user и django_session

Ответы [ 6 ]

44 голосов
/ 29 сентября 2014

Этот ответ публикуется через пять лет после первоначального вопроса, но эта тема SO является одним из лучших результатов Google при поиске решения этой проблемы (и это все еще не поддерживается из коробки с Django). ).

У меня есть альтернативное решение для случая использования, когда вас интересуют только зарегистрированные пользователи, использующие дополнительную модель UserSession для сопоставления пользователей с их сессиями, что-то вроде этого:

from django.conf import settings
from django.db import models
from django.contrib.sessions.models import Session

class UserSession(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    session = models.ForeignKey(Session)  

Затем вы можете просто сохранить новый экземпляр UserSession в любое время, когда пользователь входит в систему:

from django.contrib.auth.signals import user_logged_in

def user_logged_in_handler(sender, request, user, **kwargs):
    UserSession.objects.get_or_create(user = user, session_id = request.session.session_key)

user_logged_in.connect(user_logged_in_handler)

И, наконец, когда вы хотите перечислить (и, возможно, очистить) сеансы для конкретного пользователя:

from .models import UserSession

def delete_user_sessions(user):
    user_sessions = UserSession.objects.filter(user = user)
    for user_session in user_sessions:
        user_session.session.delete()

В этом вся суть, если вы хотите больше подробностей, у меня есть сообщение в блоге , в котором оно освещается.

28 голосов
/ 25 октября 2008

Это несколько сложно сделать, потому что не каждый сеанс обязательно связан с аутентифицированным пользователем; Каркас сеансов Django также поддерживает анонимные сеансы, и любой, кто посещает ваш сайт, будет иметь сеанс независимо от того, вошли ли они в систему.

Это еще более усложняется тем фактом, что сам объект сеанса сериализуется - поскольку Django не имеет возможности узнать, какие именно данные вы хотите сохранить, он просто сериализует словарь данных сеанса в строку (используя стандарт Python модуль "pickle") и вставляет его в вашу базу данных.

Если у вас есть ключ сеанса (который будет отправлен браузером пользователя в качестве значения cookie «sessionid»), самый простой способ получить данные - просто запросить в таблице сеансов сеанс с этим ключом, который возвращает объект Session. Затем вы можете вызвать метод get_decoded () этого объекта, чтобы получить словарь данных сеанса. Если вы не используете Django, вы можете посмотреть исходный код (django / contrib / session / models.py), чтобы увидеть, как десериализуются данные сеанса.

Однако, если у вас есть идентификатор пользователя, вам нужно будет перебрать все объекты Session, десериализовать каждый из них и найти тот, у которого есть ключ с именем "_auth_user_id" и для которого значение этого ключа идентификатор пользователя.

26 голосов
/ 04 июня 2011

Я нашел этот фрагмент кода

from django.contrib.sessions.models import Session
from django.contrib.auth.models import User

session_key = '8cae76c505f15432b48c8292a7dd0e54'

session = Session.objects.get(session_key=session_key)
uid = session.get_decoded().get('_auth_user_id')
user = User.objects.get(pk=uid)

print user.username, user.get_full_name(), user.email

здесь http://scottbarnham.com/blog/2008/12/04/get-user-from-session-key-in-django/

Еще не подтвердил, но выглядит довольно прямо.

24 голосов
/ 26 октября 2008

Изменение таблицы django_session для добавления явного user_id может значительно облегчить жизнь. Предполагая, что вы делаете это (или что-то подобное), вот четыре подхода к тому, чтобы подбирать вещи по своему вкусу:

Вилка кода django.contrib.session. Я знаю, я знаю, это ужасная вещь, чтобы предложить. Но это всего 500 строк, включая все бэкэнды и минус тесты. Это довольно просто взломать. Это лучший маршрут, только если вы собираетесь что-то серьезно изменить.

Если вы не хотите раскошелиться, попробуйте подключиться к сигналу Session.post_save и заглянуть туда.

Или вы можете MonkeyPatch contrib.session.models.Session.save(). Просто оберните существующий метод (или создайте новый), разбейте / синтезируйте любые значения, которые вам нужны, сохраните их в ваших новых полях, а затем super(Session, self).save().

Еще один способ сделать это - добавить 2 (да, два) класса промежуточного программного обеспечения - один до и один после SessionMiddleware в ваш файл settings.py . Это из-за способа обработки промежуточного программного обеспечения. Тот, который указан после SessionMiddleware, получит по входящему запросу запрос с уже подключенным сеансом. Приведенный выше может выполнить любую обработку ответа и / или изменить / повторно сохранить сеанс.

Мы использовали вариацию этого последнего метода для создания псевдосеансов для пауков поисковых систем, чтобы предоставить им специальный доступ к материалам, которые обычно доступны только для членов. Мы также обнаруживаем входящие ссылки, где поле REFERER, из соответствующей поисковой системы, и мы даем пользователю полный доступ к этой статье.

Обновление:

Мой ответ сейчас довольно древний, хотя он все еще в основном правильный. См. Гораздо более свежий ответ @ Gavin_Ballard (29.09.2014) ниже для еще одного подхода к этой проблеме.

7 голосов
/ 04 февраля 2011

Питер Роуэлл, спасибо за ваш ответ. Это была огромная помощь. Это то, что я сделал, чтобы заставить его работать. Нужно было изменить только один файл в djang.contrib.sessions.

В django / contrib / session / models.py добавьте user_id в таблицу (добавьте в таблицу DB вручную или удалите таблицу и запустите manage.py syncdb).

class Session(models.Model):

    ...

    user_id = models.IntegerField(_('user_id'), null=True)

    ...

    def save(self, *args, **kwargs):
        user_id = self.get_decoded().get('_auth_user_id')
        if ( user_id != None ):
            self.user_id = user_id

        # Call the "real" save() method.
        super(Session, self).save(*args, **kwargs)

Теперь, по вашему мнению, вы регистрируетесь (если вы используете базовый логин django, вам придется его переопределить)

# On login, destroy all prev sessions
        # This disallows multiple logins from different browsers
        dbSessions = Session.objects.filter( user_id = request.user.id )
        for index, dbSession in enumerate( dbSessions ):
            if ( dbSession.session_key != request.session.session_key ):
                dbSession.delete()

Это сработало для меня.

6 голосов
/ 18 июля 2012

Я столкнулся с этой проблемой, когда хотел выгнать спаммера. Кажется, что установка их учетной записи в «неактивном» не достаточно, потому что они все еще могут войти на их предыдущей сессии. Итак - как удалить сеанс для определенного пользователя или как намеренно прекратить сеанс для конкретного пользователя?

Ответ состоит в том, чтобы использовать поле last_login для отслеживания времени, когда сеанс был отключен, что говорит о том, что expire_date - это две недели спустя, что позволяет вам выполнить полезный фильтр для таблицы сеансов:

from django.contrib.sessions.models import Session
from django.contrib.auth.models import User
from datetime import datetime
from dateutil.relativedelta import relativedelta

baduser = User.objects.get(username="whoever")     
two_weeks = relativedelta(weeks=2)
two_hours = relativedelta(hours=2)
expiry = baduser.last_login + two_weeks
sessions = Session.objects.filter(
    expire_date__gt=expiry - two_hours,
    expire_date__lt=expiry + two_hours
) 
print sessions.count() # hopefully a manageable number

for s in sessions:
    if s.get_decoded().get('_auth_user_id') == baduser.id:
        print(s)
        s.delete()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...