Django4.0 使用會話-在視圖中使用會話

2022-03-16 18:00 更新

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

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

class backends.base.SessionBase

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

會話序列化

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

綁定序列化

class serializers.JSONSerializer

來自 ?django.core.signing? 的JSON序列化器的裝飾器??梢灾恍蛄谢緮?shù)據(jù)類型。
另外,因為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'

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

class serializers.PickleSerializer

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

編寫自定義的序列化器

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

會話對象指南

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

示例

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

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!')

這是一個記錄站點(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ù)據(jù)意外泄露。它調(diào)用 ?request.session? 的 ?flush()? 方法。我們使用這個例子作為示范如何使用會話對象,而不是完整的 ?logout()? 實現(xiàn)。


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號