Подтвердить что ты не робот

Как искать сеанс django для конкретного пользователя?

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Update:

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

Ответ 2

Этот ответ публикуется через пять лет после первоначального вопроса, но этот поток 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()

Что орехи и болты его, если вы хотите более подробно, у меня есть сообщение в блоге, охватывающее его.

Ответ 3

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

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

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

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

Ответ 4

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

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/

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

Ответ 5

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

В django/contrib/sessions/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

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

Ответом является поле пользователя 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()