Сохранение переменных сеанса при входе в систему - PullRequest
4 голосов
/ 24 ноября 2011

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

Сеансы Django поддерживают ключ сеанса в файле cookie для отслеживания сеанса пользователя. Насколько я понимаю, этот ключ меняется, когда пользователь входит в систему.

a) Означает ли это, что все переменные сеанса удаляются при входе в систему или существует какая-либо пасха

б) В случае невозможности сохранения настроек при входе в систему, является ли настройка файлов cookie вручную лучшим способом для продолжения? Я представляю себе сценарий вроде:

  • при выходе из системы сохранить настройки в cookie
  • при входе в систему, скопировать настройки в переменную сеанса и записать в БД (через сигнал?)
  • при выходе из системы, обновлять куки с настройками (через сигнал?)

Обновление

Мне удалось получить эту функциональность, сохранив настройки в объекте профиля пользователя, а также в файле cookie (эти настройки никак не чувствительны). Когда пользователь вошел в систему, настройки его профиля имеют преимущество. Если вы не авторизованы, предпочтение отдается cookie

Ответы [ 5 ]

8 голосов
/ 25 января 2017

При входе в систему Django вызывает session.flush() или session.cycle_key(), что гарантирует, что ничего из старого сеанса не сохранится. Это мера безопасности, которая защищает вас от уязвимостей фиксации сеанса. Поэтому, применяя это решение, помните, что найти переменные, которые вы хотите сохранить.

Если вы хотите сохранить какое-то состояние, вам нужно будет восстановить его после того, как имя пользователя было введено.

Решение Chase Seibert было отличным началом, оно было очень небезопасным из-за проблем с безопасностью потоков в этом коде. Вы можете найти улучшенную версию здесь, которая безопасна для использования:

class persist_session_vars(object):
    """
    Some views, such as login and logout, will reset all session state.
    (via a call to ``request.session.cycle_key()`` or ``session.flush()``).
    That is a security measure to mitigate session fixation vulnerabilities.

    By applying this decorator, some values are retained.
    Be very aware what find of variables you want to persist.
    """

    def __init__(self, vars):
        self.vars = vars

    def __call__(self, view_func):

        @wraps(view_func)
        def inner(request, *args, **kwargs):
            # Backup first
            session_backup = {}
            for var in self.vars:
                try:
                    session_backup[var] = request.session[var]
                except KeyError:
                    pass

            # Call the original view
            response = view_func(request, *args, **kwargs)

            # Restore variables in the new session
            for var, value in session_backup.items():
                request.session[var] = value

            return response

        return inner

и теперь вы можете написать:

from django.contrib.auth import views

@persist_session_vars(['some_field'])
def login(request, *args, **kwargs):
    return views.login(request, *args, **kwargs)

А для представлений на основе классов (Джанго-Аллах):

import allauth.account.views as auth_views
from django.utils.decorators import method_decorator

@method_decorator(persist_session_vars(['some_field']), name='dispatch')
class LoginView(auth_views.LoginView):
    pass

и используйте это представление в шаблонах URL:

import allauth.urls
from django.conf.urls import include, url

from . import views

urlpatterns = [
    # Views that overlap the default:
    url(r'^login/$', views.LoginView.as_view(), name='account_login'),

    # default allauth urls
    url(r'', include(allauth.urls)),
]
2 голосов
/ 24 ноября 2011

Когда вы входите / выходите из системы, Django сбрасывает все сессии, если другой пользователь входит в систему (request.session.flush () в auth / init .py).

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

1 голос
/ 24 ноября 2011

пользовательских данных, которые сохраняются, звучит так, как будто они должны жить в чем-то вроде UserProfile модель

0 голосов
/ 30 декабря 2015

Вы можете создать форму Mixin, которая позволит вам сохранять значения формы в сеансе пользователя (который не требует их входа в систему). Это полезно для таких вещей, как параметры фильтра / сортировки в общедоступном отчете о табличном представлении, где вы хотите, чтобы параметры фильтра оставались постоянными при обновлениях.

filter form screenshot

Вид:

def list_states(request):
    if request.method == 'GET':
        form = StateListFilterForm().load_from_session(request.session)
    elif request.method == 'POST':
        form = StateListFilterForm(request.POST)
        form.persist_to_session()
    return render('forms/state_list.html', RequestContext(request, {'state_form': form})

Форма:

class PersistableMixin:
    def persist_to_session(form, session):
        for key in form.fields.keys():
            val = getattr(form, 'cleaned_data', form.data).get(key, None)
            if val:  # will not store empty str values
                session[key] = val
        return True

    def load_from_session(form, session):
        for key in form.fields.keys():
            saved_val = session.get(key, '')
            if saved_val:  # will not load empty str values
                form.fields[key].initial = saved_val
        return form


class StateListFilterForm(forms.Form, PersistableMixin):
    states = forms.MultipleChoiceField(required=False, choices=US_STATES)
0 голосов
/ 29 июня 2012

Я действительно думаю, что ваш первоначальный дизайн имел смысл.Если вы хотите сохранить некоторые переменные сеанса через границу входа в систему / выхода из системы, вы можете сделать что-то вроде этого.

from functools import wraps

class persist_session_vars(object):
    """ Some views, such as login and logout, will reset all session state.
    However, we occasionally want to persist some of those session variables.
    """

    session_backup = {}

    def __init__(self, vars):
        self.vars = vars

    def __enter__(self):
        for var in self.vars:
            self.session_backup[var] = self.request.session.get(var)

    def __exit__(self, exc_type, exc_value, traceback):
        for var in self.vars:
            self.request.session[var] = self.session_backup.get(var)

    def __call__(self, test_func, *args, **kwargs):

        @wraps(test_func)
        def inner(*args, **kwargs):
            if not args:
                raise Exception('Must decorate a view, ie a function taking request as the first parameter')
            self.request = args[0]
            with self:
                return test_func(*args, **kwargs)

        return inner

Вы бы добавили этот декоратор в любое представление, из которого вызываете auth.login / logout.Если вы делегируете встроенный вид для них, вы можете легко обернуть их.

from django.contrib.auth import views

@persist_session_vars(['HTTP_REFERER'])
def login(request, *args, **kwargs):
    return views.login(request, *args, **kwargs)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...