Django - cookie 、session
目錄
1-2 Session - 儲存在伺服器的key-value結構資料
五、Django中的Session配置 - 可放置於快取、redis(記憶體資料庫)等資料庫、settings檔案等 -- 可以同時配置多個區域
一、cookie、session - 概念
注意:HTTP協議是無狀態協議,每個請求都是獨立,無法記錄前一次請求的狀態。但HTTP協議中可以使用Cookie來完成會話跟蹤。在Web開發中,使用session來完成會話跟蹤,session底層依賴Cookie技術。
1-1 cookie - 儲存在瀏覽器的key-value結構資料
key-value結構的資料,由伺服器接受響應後,傳送給客戶端瀏覽器。客戶端瀏覽器會把Cookie儲存起來,當下一次再訪問伺服器時把Cookie再發送給伺服器。
注意:在瀏覽器中檢視cookie資料內容:F12-network-cookies檔案
1-1-1 cookie 原理
由伺服器產生內容,傳送給瀏覽器,瀏覽器收到請求後儲存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上Cookie,這樣伺服器就能通過Cookie的內容來判斷這個是“誰”了。
1-1-2 cookie 規範
Cookie大小上限為4KB;
一個伺服器最多在客戶端瀏覽器上儲存20個Cookie;
一個瀏覽器最多儲存300個Cookie;
上面的資料只是HTTP的Cookie規範,但在瀏覽器大戰的今天,一些瀏覽器為了打敗對手,為了展現自己的能力起見,可能對Cookie規範“擴充套件”了一些,例如每個Cookie的大小為8KB,最多可儲存500個Cookie等!但也不會出現把你硬碟佔滿的可能! 注意,不同瀏覽器之間是不共享Cookie的。也就是說在你使用IE訪問伺服器時,伺服器會把Cookie發給IE,然後由IE儲存起來,當你在使用FireFox訪問伺服器時,不可能把IE儲存的Cookie傳送給伺服器
1-1-3 cookie的覆蓋 - 伺服器端傳送重複的Cookie那麼會覆蓋原有的Cookie
例如:
客戶端的第一個請求伺服器端傳送的Cookie是:Set-Cookie: a=A; 第二請求伺服器端傳送的是:Set-Cookie: a=AA。
那麼客戶端只留下一個Cookie,即:a=AA。
1-2 Session - 儲存在伺服器的key-value結構資料
Cookie雖然在一定程度上解決了“保持狀態”的需求,但是由於Cookie本身最大支援4096位元組,以及Cookie本身儲存在客戶端,可能被攔截或竊取,session 產生將 cookie儲存在伺服器,有較高的安全性。
總結而言:Cookie彌補了HTTP無狀態的不足,讓伺服器知道來的人是“誰”;但是Cookie以文字的形式儲存在本地,自身安全性較差;所以我們就通過Cookie識別不同的使用者,對應的在Session裡儲存私密的資訊以及超過4096位元組的文字。
二、 Django中操作cookie
2-1 獲取cookie
''' request.COOKIES['key'] request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None) ''' def set_cookie(request): obj = HttpResponse('hello set_cookie') # 普通設定cookie # obj.set_cookie('name', 'hello') # Set-Cookie:name=hello; Path=/ obj.set_signed_cookie('name','hello',salt='salt-set-cookie',max_age=10,) # Set-Cookie:name=hello:1gPjkJ:GBRTD7o3mBHO…50:06 GMT; Max-Age=10; Path=/ return obj
引數:
- default: 預設值
- salt: 加密鹽
- max_age: 後臺控制過期時間,單位為s
2-2 設定cookie
''' rep = HttpResponse(...) rep = render(request, ...) rep.set_cookie(key,value) rep.set_signed_cookie(key,value,salt='加密鹽') ''' def get_cookie(request): print(request.COOKIES) # {'name': 'hello'} print(type(request.COOKIES)) # <class 'dict'> # 簡單獲取cookie的方式 # name = request.COOKIES['name'] # name = request.COOKIES.get('name') # Cookie:name=hello; name = request.get_signed_cookie('name', default=None, salt='salt', max_age=5) # Cookie:name=hello:1gPjlG:uWQ2P9PhBHRZxRtx4mY4k7QDk84 print(name) # hello obj = HttpResponse('hello get_cookie') return obj
引數:
- key, 鍵
- value='', 值
- max_age=None, 超時時間 cookie需要延續的時間(以秒為單位)如果引數是\ None`` ,這個cookie會延續到瀏覽器關閉為止
- expires=None, 超時時間(IE requires expires, so set it if hasn't been already.),使用datatime物件
- path='/', Cookie生效的路徑,/ 表示根路徑,即指定路徑能收到網頁村粗的cookie
注意:根路徑的cookie可以被任何url的頁面訪問,瀏覽器只會把cookie回傳給帶有該路徑的頁面,這樣可以避免將cookie傳給站點中的其他的應用。- domain=None, Cookie生效的域名 你可用這個引數來構造一個跨站cookie。
如, domain=".example.com"所構造的cookie對下面這些站點都是可讀的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。
如果該引數設定為 None ,cookie只能由設定它的站點讀取- secure=False, 瀏覽器將通過HTTPS來回傳cookie
- httponly=False 只能http協議傳輸,無法被JavaScript獲取(不是絕對,底層抓包可以獲取到也可以被覆蓋)
2-3 刪除cookie
def delete_cookie(request): obj= HttpResponse('ok') # 指定刪除名字是name的cookie obj.delete_cookie('name') return obj
三、cookie 實現登陸校驗
需求分析:
- 未登入的情況下查詢購物頁面,購物頁面自動返回登入頁進行登陸
- 若從購物頁面跳到登入頁,則登陸完畢跳轉回購物頁
- 若直接開啟登陸選項進行登陸,則跳轉回指定主頁
from django.shortcuts import render, HttpResponse, redirect # Create your views here. # 登陸判斷裝飾器 def login_auth(func): def inner(request, *args, **kwargs): url = request.get_full_path() print(url) is_login = request.COOKIES.get('is_login') if is_login: res = func(request, *args, **kwargs) return res else: # 返回login頁面重新登陸,next表示從哪個頁面返回 return redirect('/app03/login/?next=%s' % url) return inner def login(request): if request.method == 'GET': return render(request, 'aPP_3_login.html') else: # 從url內獲取next屬性值 next = request.GET.get('next') name = request.POST.get('name') pwd = request.POST.get('pwd') if name == 'name' and pwd == '123': if next: # 若為他頁跳轉,返回跳轉前他頁(主頁面) obj = redirect(next) else: # 若非他頁跳轉,返回指定頁面(主頁面) obj = redirect('/app03/index/') obj.set_cookie('is_login', True) return obj else: return HttpResponse('使用者名稱或密碼錯誤') @login_auth def shopping(request): return HttpResponse('確認登陸,可進行購物操作')
四、Django操作Session
# 獲取Session中資料 request.session['k1'] request.session.get('k1',None) ''' 取值流程 獲取cookie中的隨機字串,根據資料庫session表中隨機字串查詢到session_data字典,從字典中獲取指定key的value ''' # 設定Session中資料 request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在則不設定 ''' 設定流程 生產一個隨機字串,並存儲到資料庫中 - 隨機字串 {'資料名':資料},向cookie中寫入sessionid(用於儲存隨機字串) ''' # 刪除Session中資料 del request.session['k1'] request.session.delete() # 當前會話的所有資料,僅刪除資料庫內的記錄 request.session.flush() # 刪除 瀏覽器內cookie快取、資料庫內記錄資料 # .flush() 用於確保前面的會話資料不可以再次被使用者的瀏覽器訪問 # 例如,django.contrib.auth.logout() 函式中就會呼叫它。 ''' 刪值流程 獲取cookie字串查詢,在資料庫中獲取相應session表中記錄物件進行刪除 ''' # 所有 鍵、值、鍵值對 request.session.keys() request.session.values() request.session.items() # 同上,返回迭代器 request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 會話session的key - 取到隨機字串,瀏覽器帶過來的cookie值 request.session.session_key # 內部封裝 request.COOKIES.get('sessionid') # 將所有Session失效日期小於當前日期的資料刪除 request.session.clear_expired() # 檢查會話session的key在資料庫中是否存在 request.session.exists("session_key") # 設定會話Session和Cookie的超時時間 request.session.set_expiry(value) ''' * 如果value是個整數,session會在些秒數後失效。 * 如果value是個datatime或timedelta,session就會在這個時間後失效。 * 如果value是0,使用者關閉瀏覽器session就會失效。 * 如果value是None,session會依賴全域性session失效策略。 '''
4-1 set、get練習
報錯資訊1:查詢不到sessiong表
問題原因:未查詢到session表,僅僅是對資料進行執行,仍需要資料庫的遷移操作
解決方法:進行資料庫的兩條遷移命令
from django.shortcuts import render, HttpResponse # Create your views here. def set_session(request): # 寫session,幹了三件事(每個瀏覽器會生成一個隨機字串) # 隨機字串是跟瀏覽器相關的,資料是跟賬號相關的 request.session['name'] = 'hello' # request.session['age']='18' # request.session['sex']='女' ''' 1 生成隨機字串:dfasfasdfa 2 去資料庫儲存 隨機字串 值 (字典形式) 超時時間 dfasfasdfa {'name':'hello','age':18,'sex':'女'} 超時時間 3 寫入scookie(set_cookie('sessionid','dfasfasdfa')) ''' return HttpResponse('ok') def get_session(request): # 取session 取name這個欄位對應的值 name=request.session['name'] print(name) # 取到隨機字串,瀏覽器帶過來的cookie的值 print(request.session.session_key) # dg6271ulrx1iftozcwaunk0fx871naup # 內部 # request.COOKIES.get('sessionid') # 刪除資料庫的資料(內部) # 取出cookie,隨機字串,去資料庫刪除隨機字串是當前值的記錄 # request.session.delete() # 即刪資料庫,又刪瀏覽器的cookie # request.session.flush() return HttpResponse('get_session')
五、Django中的Session配置 - 可放置於快取、redis(記憶體資料庫)等資料庫、settings檔案等 -- 可以同時配置多個區域
1. 資料庫Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(預設) 2. 快取Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的快取別名(預設記憶體快取,也可以是memcache),此處別名依賴快取的設定 3. 檔案Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 快取檔案路徑,如果為None,則使用tempfile模組獲取一個臨時地址tempfile.gettempdir() 4. 快取+資料庫 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 5. 加密Cookie Session SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 其他公用設定項: 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,預設修改之後才儲存(預設)
六、session - 實現登陸校驗
6-1 基於CBV + 裝飾器 實現登入驗證
from django.shortcuts import render, HttpResponse, redirect from django.views import View from django.utils.decorators import method_decorator def login_auth(func): def inner(request, *args, **kwargs): url = request.get_full_path() print(url) # is_login = request.COOKIES.get('is_login') is_login = request.session.get('is_login',None) if is_login: res = func(request, *args, **kwargs) return res else: # 返回login頁面重新登陸,next表示從哪個頁面返回 return redirect('/app03/login/?next=%s' % url) return inner class Login(View): # 若資料請求為get請求觸發 def get(self, request): return render(request, 'aPP_3_login.html') # 若資料請求為post請求觸發 def post(self, request): # 從url內獲取next屬性值 next = request.GET.get('next') name = request.POST.get('name') pwd = request.POST.get('pwd') if name == 'name' and pwd == '123': if next: # 若為他頁跳轉,返回跳轉前他頁(主頁面) obj = redirect(next) else: # 若非他頁跳轉,返回指定頁面(主頁面) obj = redirect('/shopping/') # obj.set_cookie('is_login', True) request.session['is_login'] = True return obj else: return HttpResponse('使用者名稱或密碼錯誤') # @method_decorator(login_auth, name='get') # 指定get方法進行login驗證 # @method_decorator(login_auth,name='post') # 指定post方法進行login驗證 # @method_decorator(login_auth,name='dispatch') # dispatch的便捷寫法 class Shopping(View): # 給內建dispatch方法新增裝飾器,那麼下面所有的get,post等其他方法都會新增 @method_decorator(login_auth) def dispatch(self, request, *args, **kwargs): obj = super().dispatch(request, *args, **kwargs) return obj # @method_decorator(login_auth) # 單獨指定get方法進行驗證 # 若資料請求為get請求觸發 def get(self, request): return HttpResponse('get-確認登陸,可進行購物操作') # 若資料請求為post請求觸發 def post(self, request): return HttpResponse('post-確認登陸,可進行購物操作')