Джанго - Управление сессиями - PullRequest
0 голосов
/ 08 марта 2019

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

Я реализую это в моем models.py:

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, on_delete=models.CASCADE)
    session = models.OneToOneField(Session, on_delete=models.CASCADE)


from django.contrib.auth import user_logged_in
from django.dispatch.dispatcher import receiver

@receiver(user_logged_in)
def remove_other_sessions(sender, user, request, **kwargs):
    # remove other sessions
    Session.objects.filter(usersession__user=user).delete()

    # save current session
    request.session.save()

    # create a link from the user to the current session (for later removal)
    UserSession.objects.get_or_create(
        user=user,
        session=Session.objects.get(pk=request.session.session_key)
    )

В основном работает нормально, однако я заметил странное поведение.

Если я войду в систему с одной учетной записью, а затем открою окно инкогнито и войду с теми же учетными данными, первый выйдет из системы (что я и хотел).

Однако, если я войду с учетной записью, а затем закрою браузер, при следующем входе в систему я получу сообщение об ошибке:

# save current session
request.session.save()

со следующей трассировкой (без особой информации ..):

UpdateError at /

Сообщение об исключении не отправлено

Журнал консоли показывает, что ошибка исходит от

django.contrib.sessions.backends.base.UpdateError

После этого, если я обновлю страницу, я смогу успешно войти в систему.

Есть идеи о том, что может происходить?

1 Ответ

1 голос
/ 08 марта 2019

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

@receiver(user_logged_in)
def remove_other_sessions(sender, user, request, **kwargs):
    # remove other sessions
    old_sessions = Session.objects.filter(usersession__user=user)
    if request.session.session_key:
        old_sessions = old_sessions.exclude(session_key=request.session.session_key)
    old_sessions.delete()

    # save current session
    request.session.save()

    # create a link from the user to the current session (for later removal)
    UserSession.objects.get_or_create(
        user=user,
        session=Session.objects.get(pk=request.session.session_key)
    )
...