在檢視中使用會話

weixin_33816300發表於2018-03-12

當SessionMiddleware被啟用時,每個HttpRequest物件 - 任何Django檢視函式的第一個引數 - 將具有會話屬性,這是一個類似字典的物件。 您可以閱讀並在您的檢視中的任何位置寫入request.session。 您也可以多次編輯它。

所有會話物件都從基類backends.base.SessionBase繼承。 它有以下標準字典方法:

  • getitem(key)
  • setitem(key, value)
  • delitem(key)
  • contains(key)
  • get(key, default=None)
  • pop(key)
  • keys()
  • items()
  • setdefault()
  • clear()

它也有這些方法:

flush()

從會話中刪除當前會話資料並刪除會話cookie。如果要確保先前的會話資料不能從使用者的瀏覽器再次訪問(例如,django.contrib.auth.logout()函式呼叫它),則使用此選項。

set_test_cookie()

設定測試Cookie以確定使用者的瀏覽器是否支援Cookie。由於Cookie的工作方式,您將無法在使用者的下一頁請求之前對其進行測試。請參閱“設定測試cookie”
以下更多資訊。

test_cookie_worked()

根據使用者的瀏覽器是否接受測試Cookie,返回True或False。由於Cookie的工作方式,您必須在先前的單獨頁面請求中呼叫set_test_cookie()。有關更多資訊,請參見下面的“設定測試cookie”。

delete_test_cookie()

刪除測試cookie。用它來清理你自己。

set_expiry(value)

設定會話的到期時間。您可以傳遞許多不同的值:

  • 如果value是一個整數,那麼會話將在多秒鐘不活動之後過期。
    例如,呼叫request.session.set_expiry(300)會使會話在5分鐘內過期。

  • 如果value是日期時間或timedelta物件,則會話將在該特定日期/時間過期。 請注意,如果您使用PickleSerializer,則datetime和timedelta值僅可序列化。

  • 如果值為0,則使用者的會話cookie將在使用者的Web瀏覽器關閉時到期。

  • 如果值為無,會話將恢復為使用全域性會話到期策略。
    閱讀會話不被視為有效到期的活動。 會話過期是從上次會話被修改時計算出來的。

get_expiry_age()

返回此會話到期之前的秒數。 對於沒有自定義到期的會話(或設定為在瀏覽器關閉時過期的會話),這將等於SESSION_COOKIE_AGE。 該函式接受兩個可選的關鍵字引數:

  • modification:會話的最後修改,作為日期時間物件。 預設為當前時間。

  • expiry:會話的到期資訊,作為日期時間物件,int(以秒為單位)或None。 如果存在一個值,則預設為set_expiry()儲存在會話中的值,或者是None。

get_expiry_date()

返回此會話過期的日期。 對於沒有自定義到期的會話(或設定為在瀏覽器關閉時過期的會話),這將等於從現在開始的SESSION_COOKIE_AGE秒。 該函式接受與get_expiry_age()相同的關鍵字引數。

get_expire_at_browser_close()

返回True或False,取決於使用者的Web瀏覽器關閉時使用者的會話Cookie是否過期。

clear_expired()

從會話儲存中刪除過期的會話。 這個類方法由clearsessions呼叫。

cycle_key()

在保留當前會話資料的同時建立新的會話金鑰。 django.contrib.auth.login()呼叫此方法來減輕會話固定。

會話物件準則
  • 使用普通的Python字串作為request.session上的字典鍵。 這是一個比硬性規定更重要的慣例。
  • 以下劃線開頭的會話字典鍵由Django保留供內部使用。
  • 不要用新物件重寫request.session,也不要訪問或設定它的屬性。 像Python字典一樣使用它。
會話序列化

在版本1.6之前,Django預設使用pickle將會話資料序列化,然後將其儲存在後端。如果您使用的是經過簽名的cookie會話後端,並且SECRET_KEY被攻擊者所知(在Django中沒有可能導致其洩漏的固有漏洞),攻擊者可以在會話中插入一個字串,該字串在取消時會執行伺服器上的任意程式碼。這樣做的技術很簡單,並且可以在網際網路上輕鬆獲得。

儘管cookie會話儲存器會對cookie儲存的資料進行簽名以防止篡改,但SECRET_KEY洩漏會立即升級為遠端執行程式碼的漏洞。這種攻擊可以通過使用JSON而不是pickle序列化會話資料來緩解。為了實現這一點,Django 1.5.3引入了一個新的設定SESSION_SERIALIZER來定製會話序列化格式。為了向後相容,此設定預設使用Django 1.5.x中的django.contrib.sessions.serializers.PickleSerializer,但為了加強安全性,預設為從Django 1.6開始的django.contrib.sessions.serializers.JSONSerializer。

即使在自定義序列化器中描述的警告中,我們強烈建議堅持使用JSON序列化,特別是如果您使用的是Cookie後端。

捆綁的序列

serializers.JSONSerializer
來自django.core.signing的JSON序列化程式包裝。只能序列化基本資料型別。此外,由於JSON僅支援字串鍵,請注意,在request.session中使用非字串鍵將無法按預期工作:

>>> # initial assignment
>>> request.session[0] = 'bar'
>>> # subsequent requests following serialization &
deserialization
>>> # of session data
>>> request.session[0]  # KeyError
>>> request.session['0']
'bar'

有關JSON序列化限制的更多詳細資訊,請參閱custom-serializers部分。

serializers.PickleSerializer
支援任意的Python物件,但是如上所述,如果攻擊者知道SECRET_KEY,則可能導致遠端執行程式碼漏洞。

編寫你自己的序列

請注意,與PickleSerializer不同,JSONSerializer無法處理任意Python資料型別。通常情況下,便利性和安全性之間有一個折衷。如果您希望在JSON支援的會話中儲存更高階的資料型別(包括日期時間和Decimal),則需要編寫自定義序列化程式(或在將這些值儲存到request.session中之前將這些值轉換為JSON可序列化物件)。

雖然序列化這些值非常簡單(django.core.serializers.json.DateTimeAwareJSONEncoder可能會有所幫助),但編寫一個可以可靠地取回與放入的東西相同的解碼器會更脆弱。例如,您冒著返回日期時間的風險,該日期時間實際上是恰好與日期時間相同的格式的字串)。

您的序列化程式類必須實現兩種方法,分別轉儲(self,obj)和載入(self,data)以序列化和反序列化會話資料字典。

設定測試Cookie

為了方便起見,Django提供了一種簡單的方法來測試使用者的瀏覽器是否接受cookie。只需在檢視中呼叫request.session的set_test_cookie()方法,然後在後續檢視中呼叫test_cookie_worked(),而不是在同一檢視呼叫中呼叫。

由於cookie的工作方式,set_test_cookie()和test_cookie_worked()之間的這種尷尬分裂是必要的。當你設定一個cookie時,你不能確定瀏覽器是否接受它,直到瀏覽器的下一個請求。最好使用delete_test_cookie()來清理自己。在您驗證測試cookie正常工作後執行此操作。

以下是一個典型的使用示例:

def login(request):
    if request.method == 'POST':
        if request.session.test_cookie_worked():
            request.session.delete_test_cookie()
            return HttpResponse("You're logged in.")
        else:
            return HttpResponse("Please enable cookies and try again.")
    request.session.set_test_cookie()
    return render_to_response('foo/login_form.html')

相關文章