2011-11-24 204 views
2

我想在會話變量中保存關於用戶首選項的信息。如果用戶在註銷時選擇首選項,然後再登錄,我希望維護首選項而無需重新選擇它。在登錄時保持會話變量

Django會話在Cookie中維護會話密鑰以跟蹤用戶會話。我的理解是,這關鍵是改變時,在用戶登錄。

一)這是否意味着所有的會話變量是在登錄刪除或有任何形式的逾越節

b)在沒有的情況下能夠通過登錄保存偏好設置,是否需要手動設置Cookie才能繼續?我想像一個場景,如:

  • 而註銷,維持在餅乾上登錄
  • 的喜好,喜好複製到會話變量,並寫入到數據庫
  • 上註銷,與喜好更新餅乾(通過信號?) (通過信號?)

更新

我設法在用戶節省喜好來獲取此功能配置文件對象以及Cookie中(這些首選項不以任何方式敏感)。用戶登錄後,他們的個人資料設置將優先。如果沒有登錄,則cookie偏好選擇

回答

2

當你登入/登出Django會刷新所有會話如果(request.session.flush()在認證/ 初始化的.py)其他用戶登錄。

您最好將用戶設置存儲在數據庫中,並添加一些中間件來獲取該數據並將其存儲在請求中。即堅持

+0

這基本上回答了我的問題,謝謝! –

1

用戶數據聽起來像它應該生活在像一個UserProfile模型

+0

用戶登錄後會寫入數據庫,但如果用戶沒有登錄,我仍然希望他們能夠設置首選項,一旦他們最終登錄,這些首選項將被寫入到userprofile模型,所以問題是通過登錄 –

+0

維護數據,但是你不知道它是同一個人還是同一瀏覽器的另一個用戶。所以你很樂意認爲這是同一個人? – second

+0

對於簡單的顯示設置是的,但設置數據庫對象可以標記爲「授權」,以便只有某些設置被寫入cookie,同時所有設置都被寫入登錄會話。 –

0

其實,我覺得你的初始設計是有道理的。如果你想在登錄/註銷邊界保存一些會話變量,你可以做這樣的事情。

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 /註銷。如果你委託給那些內置的視圖,你可以輕鬆地包裝它們。

from django.contrib.auth import views 

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

這是一個很好的開始,但不是線程安全的!由於'persist_session_vars'實例化了一次,所有用戶都在寫同一個'session_backup'字典(甚至使它成爲一個對象變量而不是class屬性在這裏不會改變) – vdboor

+0

當兩個用戶同時登錄時,我會收到對方的會話變量。在你的例子中,你的統計數據將關閉。但是,爲了堅持這種個人信息,它會在網站中引入巨大的安全/信息泄漏。 – vdboor

0

您可以創建一個表單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) 
3

登錄時,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) 

而對於基於類的意見(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 

並在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)), 
]