Django4.0 使用會(huì)話-在視圖中使用會(huì)話

2022-03-16 18:00 更新

當(dāng)激活 ?SessionMiddleware ?后,每個(gè) ?HttpRequest ?對(duì)象(任何 Django 視圖函數(shù)的第一個(gè)參數(shù)) 將得到一個(gè) ?session ?屬性,該屬性是一個(gè)類字典對(duì)象。

你可以在視圖中任意位置讀取它并寫入 ?request.session? 。你可以多次編輯它。

class backends.base.SessionBase

這是所有會(huì)話對(duì)象的基礎(chǔ)類。它有以下標(biāo)準(zhǔn)字典方法:

  • ?__getitem__(key)?:fav_color = request.session['fav_color']
  • ?__setitem__(key, value)?:request.session['fav_color'] = 'blue'
  • ?__delitem__(key)?:del request.session['fav_color'] 。如果給定的 key 不在會(huì)話里,會(huì)引發(fā) KeyError 。
  • ?__contains__(key)?:'fav_color' in request.session
  • ?get(key, default=None)?:fav_color = request.session.get('fav_color', 'red')
  • ?pop(key, default=__not_given)?:fav_color = request.session.pop('fav_color', 'blue')
  • ?keys()?
  • ?items()?
  • ?setdefault()?
  • ?clear()?

它也有以下方法:

  • ?flush()?:刪除當(dāng)前會(huì)話和會(huì)話cookie。如果你想確保早先的會(huì)話數(shù)據(jù)不能被用戶的瀏覽器再次訪問時(shí),可以使用這個(gè)方法(比如,django.contrib.auth.logout() 函數(shù)調(diào)用它)。
  • ?set_test_cookie()?:設(shè)置一個(gè)測(cè)試cookie來確定用戶的瀏覽器是否支持cookie。由于測(cè)試通過,你不需要在下一個(gè)頁面請(qǐng)求時(shí)再次測(cè)試它。
  • ?test_cookie_worked()?:返回 True 或 False ,這取決于用戶瀏覽器是否接受測(cè)試cookie。由于 cookie 的工作方式,你將必須在上一個(gè)獨(dú)立的頁面請(qǐng)求里調(diào)用 set_test_cookie() 。
  • ?delete_test_cookie()?:刪除測(cè)試cookie。使用完測(cè)試cookie后用它來刪除。
  • ?get_session_cookie_age()?:返回 session cookies的失效時(shí)間,以秒為單位。默認(rèn) SESSION_COOKIE_AGE 。
  • ?set_expiry(value)?:為會(huì)話設(shè)置過期時(shí)間。你可以傳遞很多不同值:如果 value 是整型,會(huì)話將在閑置數(shù)秒后過期。比如,調(diào)用 ?request.session.set_expiry(300)? 會(huì)使得會(huì)話在5分鐘后過期。如果 value 是一個(gè) datetime 或 timedelta 對(duì)象,會(huì)話將在指定的 date/time 過期。注意,如果你正在使用 ?PickleSerializer ?,那么 datetime 和 timedelta 的值只能序列化。如果值為 0,則用戶的會(huì)話 cookie 將在用戶的 Web 瀏覽器關(guān)閉時(shí)過期。如果 value 是 None ,會(huì)話會(huì)恢復(fù)為全局會(huì)話過期策略。出于過期目的,讀取會(huì)話不被視為活動(dòng)。會(huì)話過期時(shí)間會(huì)在會(huì)話最后一次*修改*后開始計(jì)算。
  • ?get_expiry_age()?:返回該會(huì)話過期的秒數(shù)。對(duì)于沒有自定義過期時(shí)間的會(huì)話(或者那些設(shè)置為瀏覽器關(guān)閉時(shí)過期的),這等同于 ?SESSION_COOKIE_AGE ?。這個(gè)函數(shù)接受兩個(gè)可選的關(guān)鍵參數(shù):?modification ?:會(huì)話的最后一次修改,當(dāng)做一個(gè) datetime 對(duì)象。默認(rèn)是當(dāng)前時(shí)間。?expiry ?:會(huì)話的過期信息,如一個(gè) datetime 對(duì)象,整數(shù)(秒)或 None。默認(rèn)為通過 set_expiry() 存儲(chǔ)在會(huì)話中的值,或 None 。
  • ?get_expiry_date()?:返回該會(huì)話的到期日期。對(duì)于沒有自定義過期的會(huì)話(或那些設(shè)置為在瀏覽器關(guān)閉時(shí)過期的會(huì)話),這將等于從現(xiàn)在開始的?SESSION_COOKIE_AGE?秒的日期。這個(gè)函數(shù)接受與 get_expiry_age() 相同的參數(shù)。
  • ?get_expire_at_browser_close()?:返回 True 或 False,具體取決于用戶的 Web 瀏覽器關(guān)閉時(shí)用戶的會(huì)話 cookie 是否會(huì)過期。
  • ?clear_expired()?:從會(huì)話存儲(chǔ)中移除過期會(huì)話。這個(gè)類方法通過 ?clearsessions ?調(diào)用。
  • ?cycle_key()?:在保留當(dāng)前會(huì)話的同時(shí)創(chuàng)建新的會(huì)話秘鑰。?django.contrib.auth.login()? 調(diào)用這個(gè)方法來防止會(huì)話固定攻擊。

會(huì)話序列化

默認(rèn)情況下,Django 序列會(huì)話數(shù)據(jù)使用 JSON 。你可以設(shè)置 ?SESSION_SERIALIZER ?來自定義會(huì)話序列化格式。即使在編寫你自己的序列化程序中描述了警告,我們?nèi)匀粡?qiáng)烈建議您堅(jiān)持JSON序列化,尤其是在您使用cookie后端的情況下。
比如,如果你使用 pickle 來序列化會(huì)話數(shù)據(jù),那么這里一個(gè)攻擊場景。如果你正在使用 ?signed cookie session backend? 并且攻擊者已經(jīng)知道了 ?SECRET_KEY ?(Django 并不存在會(huì)導(dǎo)致其泄露的固有漏洞),攻擊者可以在會(huì)話里插入一個(gè)字符串,當(dāng) ?unpickled ?時(shí),在服務(wù)器上執(zhí)行任意代碼。這樣做的技術(shù)很簡單,在互聯(lián)網(wǎng)上也很容易獲得。盡管cookie會(huì)話存儲(chǔ)會(huì)對(duì)cookie數(shù)據(jù)進(jìn)行簽名防止篡改,但是泄露 ?SECRET_KEY ?會(huì)立即升級(jí)為遠(yuǎn)程代碼執(zhí)行的漏洞。

綁定序列化

class serializers.JSONSerializer

來自 ?django.core.signing? 的JSON序列化器的裝飾器??梢灾恍蛄谢緮?shù)據(jù)類型。
另外,因?yàn)镴SON只支持字符串鍵,注意在 ?request.session? 使用非字符串鍵會(huì)無法工作:

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

同樣,數(shù)據(jù)也不能在JSON中編碼,例如像 ?\xd9? 這種非UTF8字節(jié)(會(huì)引發(fā) ?UnicodeDecodeError ?)不會(huì)被存儲(chǔ)。

class serializers.PickleSerializer

支持任何Python對(duì)象,但是,如上所述,如果 ?SECRET_KEY ?泄露,這會(huì)導(dǎo)致攻擊者執(zhí)行遠(yuǎn)程代碼的漏洞。

編寫自定義的序列化器

注意這與 ?PickleSerializer ?不同,?JSONSerializer ?不會(huì)處理任何Python數(shù)據(jù)類型。通常情況下,便利性和安全性之間要做出權(quán)衡取舍。如果你想在 JSON 支持的會(huì)話里存儲(chǔ)任何高級(jí)數(shù)據(jù)類型(比如 ?datetime ?和 ?Decimal ?),你需要編寫自己的序列化器(或者在存儲(chǔ)這類值到 ?request.session? 之前把它們轉(zhuǎn)化JSON序列化類型)。雖然序列化這些值通常很簡單( ?DjangoJSONEncoder ?或許有幫助),但編寫一個(gè)解碼器來可靠地取回你放進(jìn)去的東西就更不容易了。 例如,你要返回一個(gè)字符串格式的 ?datetime ?,但這恰好與為 ?datetime?選擇的格式相同,這樣會(huì)有風(fēng)險(xiǎn)。
你的序列化類必須實(shí)現(xiàn)兩個(gè)方法( ?dumps(self, obj) ?和? loads(self, data)? ) 來分別進(jìn)行序列化和反序列化會(huì)話數(shù)據(jù)字典。

會(huì)話對(duì)象指南

  • 在 ?request.session? 上使用普通的 Python 字符串作為字典鍵。這更多的是一種慣例而不是硬性規(guī)定。
  • 以下劃線開頭的會(huì)話字典鍵保留給 Django 作內(nèi)部使用。
  • 不要使用新對(duì)象覆蓋 ?request.session? ,不要訪問或設(shè)置它的屬性。像使用 Python 字典一樣使用它。

示例

這個(gè)簡單的視圖將一個(gè) ?has_commented ?變量在用戶評(píng)論后設(shè)置為 ?True ?。它不允許用戶發(fā)表評(píng)論多于一次:

def post_comment(request, new_comment):
    if request.session.get('has_commented', False):
        return HttpResponse("You've already commented.")
    c = comments.Comment(comment=new_comment)
    c.save()
    request.session['has_commented'] = True
    return HttpResponse('Thanks for your comment!')

這是一個(gè)記錄站點(diǎn)成員的簡單的視圖。

def login(request):
    m = Member.objects.get(username=request.POST['username'])
    if m.check_password(request.POST['password']):
        request.session['member_id'] = m.id
        return HttpResponse("You're logged in.")
    else:
        return HttpResponse("Your username and password didn't match.")

這是記錄成員退出的視圖:

def logout(request):
    try:
        del request.session['member_id']
    except KeyError:
        pass
    return HttpResponse("You're logged out.")

標(biāo)準(zhǔn)的 ?django.contrib.auth.logout()? 函數(shù)實(shí)際上比這里要多一些來防止數(shù)據(jù)意外泄露。它調(diào)用 ?request.session? 的 ?flush()? 方法。我們使用這個(gè)例子作為示范如何使用會(huì)話對(duì)象,而不是完整的 ?logout()? 實(shí)現(xiàn)。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)