1. 程式人生 > >django框架--cookie/session

django框架--cookie/session

目錄

一、http協議無狀態問題

http協議沒有提供多次請求之間的關聯功能,協議的本意也並未考慮到多次請求之間的狀態維持,每一次請求都被協議認為是一次性的。但在某些場景下,如一次登入多次訪問,我們希望可以儲存登入狀態,協議並沒有直接提供會話跟蹤的支援,需要靠其他手段來幫助實現目標。

1、對cookie的理解

  • cookie是一個key-value的資料結構(類似python字典),用於儲存需要維護狀態的資料cookiesession最大的區別是cookie的資料儲存在客戶端,而session把資料儲存在服務端。

  • cookie一般由伺服器設定,並可以存放在http

    的請求頭和響應頭中。

  • cookie由瀏覽器儲存,瀏覽器已經實現了cookie的儲存和傳送,而伺服器上對cookie的設定和接收則需要我們配置。

  • 通過cookie,可以在多個會話之間共享一些必要的資訊如登入狀態資料、歷史訪問記錄、個性化定製設定等,以實現會話跟蹤,讓使用者感覺到網站可以'記錄'自己的偏好,減少不必要的重複輸入,從而提升使用者體驗。

2、cookie的使用介面

django的服務端傳送響應有三種方式:

1. return HttpResponse()
2. return render()
3. return redirect()

這三種方法例項化的結果都是HttpResponse

類的例項,可以直接用於設定cookie。 在response物件上執行set_cookie(key,value,...)即可設定cookie, 其中特別注意cookie屬性的設定。

cookie的設定 伺服器在響應物件上進行set_cookie操作,一旦設定完成,客戶端後續的請求就可以根據cookie的屬性規則攜帶cookie資料。

def set_cookie(key, value='', max_age=None, expires=None, path='/',
               domain=None, secure=False, httponly=False, samesite=None)

cookie的獲取 伺服器在請求物件上通過request.COOKIES得到cookie字典資料,注意此處拿到的cookie資料從安全性來說是未被驗證正確性的。

@cached_property
def COOKIES(self):
    raw_cookie = get_str_from_wsgi(self.environ, 'HTTP_COOKIE', '')
    return parse_cookie(raw_cookie)

注意1:cookie在set的時候可以設定它被髮送的範圍,每個cookie都有對應的domain+path的屬性,這約束了cookie傳送範圍,只有當http的請求落在此範圍中的url,才會攜帶此cookie。

注意2:一個cookie就是一個key-value項,不過它還攜帶有屬性。一個cookies是一個字典,儲存了很多cookie項,注意單個cookie項和整個cookies字典的關係。

3、cookie的屬性

max_age:
失效延遲時間,單位是秒,設定成15秒意味著在設定完之後的15秒之內,此cookie有效,超時之後cookie失效,瀏覽器會刪除失效的cookie。此引數預設是None,代表著直到瀏覽器關閉,即預設是會話cookie。
注意:如果max_age是0,意味著讓瀏覽器立刻刪除此cookie,即此cookie即刻失效。
    
expires:
指定失效日期,同樣用於失效cookie,只不過是另一種時間指定方式。
    
domain:
此cookie可以被使用的域名範圍。
    
path:
與domain配合著使用,預設是根路徑'/',意味著在當前domain範圍下任何url都會攜帶此cookie。可以主動設定其他的路徑以縮小發送的範圍,從而約束某一個cookie項只應用於某些url。
    
secure:
預設是False,一般配合https協議使用,在https協議下,只有secure屬性是True的cookie才允許被髮送。
    
httponly:
預設是False,這意味著js也可以通過document.cookie來訪問和設定此cookie,而如果設定為True,則代表只允許服務端來訪問和設定此cookie。

4、使用cookie的問題

cookie的安全性問題 伺服器是根據客戶端傳送過來的cookie進行狀態判斷,這種儲存在客戶端的cookie資料非常容易修改和偽裝,伺服器基本無法知曉cookie的正確性,也就不能100%信任cookie的資料。 此外,cookie很容易被盜取,如果客戶端cookie裡面包含私密資料的話,就更不安全了。

cookie的覆蓋問題 在服務端上設定的新的cookie會讓客戶端更新本地cookie

cookie的合理性問題 什麼樣的資料適合放到cookie中? cookie中的資料是每次互動都要被傳輸的,所以我認為:

  • 應該是常用的資料,如果不常用只會浪費頻寬減少效率,最好是多次互動中都要使用或者修改
  • 應該是小資料量
  • 不應該是非常私密的資料,否則:要麼在客戶端上容易被盜取,要麼在傳輸中容易被擷取

所以cookie特別適合傳送sessionid,它能滿足上述所有條件。

cookie的儲存問題 cookie是客戶端臨時儲存,按規定單個cookie檔案儲存量最大是4kb,每個域下的cookie檔案不能超過20個,不應該將cookie作為儲存功能的濫用,要使用客戶端儲存功能應該啟用localstorage

cookie的訪問限制問題 jsdocument.cookie可以獲取cookie資料,將會在控制檯輸出一個字串格式的key-value資料,如果此cookie的屬性是httponly=true就不能通過此方法獲取。

三、會話跟蹤技術--session

1、對session的理解

session把資料存放在伺服器上,並使用一個標籤session-key唯一標記此資料。session-key作為cookie傳送給客戶端,即客戶端只儲存session-key,然後通過cookie傳送給服務端,以表明身份,所以sessioncookie安全。

每一次請求到達伺服器的時候,伺服器獲取cookie中儲存的session-key,並在資料庫django-session表中尋找對應的session-data,進一步處理業務邏輯。

session的使用有如下優點: 1、資料儲存在服務端,客戶端僅儲存一個senssionid 2、sessionid資料量很小,適合每次傳送 3、安全性,sessionid是一個隨機字串,不攜帶任何私密資料

2、session的使用介面

session的設定

django實現了session,幫我們完成了很多操作,且提供使用的介面非常簡單:

request.session['name'] = 'xxx'

設定session的時候會執行如下三個操作:

1、建立一個隨機字串作為sessionid
2、把sessionid作為session-key,以及一個session_data字典加入到django-session表中
3、set-cookie,把sessionid傳送給客戶端

注意1:從底層原始碼來看,session_data其實就是一個字典{},然後通過orm存到django_session表中(應該有dict-->str的序列化和加密操作)

注意2:如果發現客戶端的cookie中含有seesionid說明不是第一次登入,將會使用此sessionid並更新此sessionid對應的session_data資料

注意3:如果有兩個使用者在同一臺電腦的同一個瀏覽器上,訪問同一個url,因為sessionid是作為cookie存在,所以兩個人會使用同一個sessionid。 而對於伺服器而言,只認sessionid不認人,使用同一個sessionid的操作會覆蓋之前的資料以導致在服務端上的session_data資料會相互覆蓋,這樣的結果是資料紊亂(尤其當兩人的資料專案數量不一致時更嚴重)

session的讀取

讀取session的介面同樣很簡單:

name = request.session['name']

讀取的時候會執行如下三個操作:

1、獲取request.COOKIES中的sessionid
2、拿著sessionid作為session_key到資料庫的django-session表中查詢對應的session-data,底層就是執行orm的objects.filter(session_key=sessionid)
3、獲取session-data中的資料並進一步處理

session的刪除

刪除session的介面:

1、del request.session[xxx]   # 刪除一個會話資料屬性
2、request.session.flush()    # 刪除所有會話資料

清空會話資訊時會執行如下操作:

1、刪除django-session表中的session-key=sessionid的記錄,底層操作就是執行orm的objects.filter(session_key=sessionid).delete()
2、刪除response中的cookie裡的sessionid記錄

注意1:伺服器把sessionid作為cookie的資料發給客戶端儲存,一般是會話cookie即不關閉瀏覽器程式就可以一直保持會話跟蹤。但一旦客戶端關閉了瀏覽器,則此sessionid便不再有效。但django頒發的cookie預設有效時間是2周,所以cookie會被儲存到客戶端硬碟上,即使關閉了瀏覽器也繼續儲存。

注意2:因為伺服器無法獲知客戶端瀏覽器將會在什麼時候關閉,更無法獲知瀏覽器什麼時候會執行清空cookie的操作。客戶端一般只有在logout的時候才會主動告知刪除session,其他情況下瀏覽器不會主動告知,所以伺服器的session不能無限儲存,被迫要設定失效時間(不然儲存空間浪費),在一定時間內如果還沒有使用者重新訪問此session,便被服務端認為此使用者已失效,進而可以刪除session資料。

3、session的屬性

settings中還可以配置全域性的session屬性:

# settings.py檔案

    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(預設)
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie儲存在瀏覽器上時的key,即:sessionid=隨機字串(預設)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie儲存的路徑(預設)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie儲存的域名(預設)
    SESSION_COOKIE_SECURE = False                            # 是否Https傳輸cookie(預設)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支援http傳輸(預設)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(預設)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否關閉瀏覽器使得Session過期(預設)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次請求都儲存Session,預設修改之後才儲存(預設)

4、使用session的問題

1、session的正常工作依賴於cookie的啟用,如果客戶端禁用cookie功能,該如何保證session正常工作?---重寫URL

2、同一臺電腦同一個瀏覽器,訪問同一個url,儲存著同一個sessionid,如何處理多使用者使用同一sessionid登入而導致的資料紊亂問題?---使用使用者認證元件,使用賬戶密碼來區別使用者

四、總結

1、cookie和session都是為了解決http協議自身並不支援狀態維持的缺點。 2、會話跟蹤的目的是為了讓多次請求之間可以共享資料,以提供更好的使用者體驗。 3、cookie和session都需要儲存狀態維持資料,只不過cookie是儲存在客戶端,session是儲存在服務端。 4、分析和研究兩者的技術相同點和區別有助於加深對會話跟蹤的理解和使用。