跨登录持久化会话变量

Tim*_*ony 4 django

我想在会话变量中保存有关用户首选项的信息.如果用户在注销时选择首选项然后再登录,我希望保留首选项而无需重新选择它.

Django会话在cookie中维护会话密钥以跟踪用户会话.我理解它的方式,当用户登录时,该密钥会被更改.

a)这是否意味着所有会话变量在登录时被删除或是否存在任何类型的逾越节

b)如果无法在登录中保存首选项,那么手动设置cookie是最佳方式吗?我想象一个场景:

  • 注销时,保持cookie中的首选项
  • 登录时,将首选项复制到会话变量并写入db(通过信号?)
  • 注销时,用首选项更新cookie(通过信号?)

更新

我设法通过在用户的配置文件对象中以及在cookie中保存首选项来获得此功能(这些首选项在任何方面都不敏感).当用户登录时,他们的配置文件设置优先.未登录时,将选择cookie首选项

vdb*_*oor 8

登录后,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
Run Code Online (Sandbox Code Playgroud)

现在你可以写:

from django.contrib.auth import views

@persist_session_vars(['some_field'])
def login(request, *args, **kwargs):
    return views.login(request, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

对于基于类的视图(django-allauth):

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
Run Code Online (Sandbox Code Playgroud)

并在网址模式中使用该视图:

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)),
]
Run Code Online (Sandbox Code Playgroud)


Wil*_*ian 3

当您登录/注销时,如果另一个用户登录(auth/ init .py 中的 request.session.flush() ),Django 将刷新所有会话。

您最好将用户设置存储在数据库中,并添加一些中间件来获取该数据并将其存储在您的请求中。