文章目錄
- Cookie的介紹
- Cookie的由來
- 什么是Cookie
- Cookie原理
- Cookie覆蓋
- 瀏覽器查看Cookie
- 在Django中操作Cookie
- 設置Cookie
- 查詢瀏覽器攜帶的Cookie
- 刪除Cookie
- Cookie校驗登錄
- session
Cookie的介紹
Cookie的由來
首先我們都應該明白HTTP協議是無連接的。
無狀態的意思是每次請求都是獨立的,它的執行情況和結果與前面的請求和之后的請求都無直接關系,它不會受前面的請求響應情況直接影響,也不會直接英系那個后面的請求響應情況。
所以對服務端來說,每一次請求都是全新的。
狀態也就是說在于服務端進行連接的過程中產生的數據,基于HTTP無連接的特性,在下一次與服務端進行連接之后又是一次全新的狀態,之前的狀態不會保存絲毫。
如果說我們要保存狀態的話,便于下一次或更多次于服務端進行連接都擁有之前的狀態,那么Cookie就誕生在這種需求下。
什么是Cookie
其實Cookie是key-value結構,類似于一個python中的字典。隨著服務器端的響應發送給客戶端瀏覽器。然后客戶端瀏覽器會把Cookie保存起來,當下一次再訪問服務器時把Cookie再發送給服務器。Cookie是由服務器創建,然后通過響應發送給客戶端的一個鍵值對。客戶端會保存Cookie,并會標注出Cookie的來源(哪個服務器的Cookie)。當客戶端向服務器發出請求時會把所有這個服務器Cookie包含在請求中發送給服務器,這樣服務器就可以識別客戶端了!
Cookie原理
Cookie的工作原理:在服務器產生后Cookie發送給瀏覽器,然后瀏覽器將其保存在本地;下次瀏覽器訪問服務器時攜帶這個Cookie,那么服務端就能根據這個Cookie內容判斷這個瀏覽器是誰了。
注意:不同瀏覽器之間是不共享Cookie的。也就是說在你使用IE訪問服務器時,服務器會把Cookie發給IE,然后由IE保存起來,當你使用Chrome訪問服務器時,不可能把IE保存的Cookie發送給服務器。
Cookie覆蓋
服務端重復發送Cookie是會覆蓋瀏覽器原有Cookie的,例如:瀏覽器第一次請求服務端返回的Cookie是:name:jack;瀏覽器第二次請求之后服務端又發送了Cookie給瀏覽器:name:tom;那么瀏覽器只會留下新的Cookie,也就是:name:tom;
注意:如果key不一樣的話則不會覆蓋,因為一個Cookie可以由好很多key-value組成
瀏覽器查看Cookie
window可以通過F12打開開發者選項,選擇Application選項下面的Cookies
在已經開啟的頁面使用開發者選項可以看不到內容,我們再刷新一下頁面就可以了。
在Django中操作Cookie
Django就是我們的服務端,瀏覽器向它發送請求我們可以返回一個Cookie。
設置Cookie
我們可以給基于HttpResponse類返回數據到瀏覽器的方法設置Cookie,如:render、redirect、JsonResponse等
request = HttpResponse('...')data = render('...')response.set_cookie(key,value)data.set_cookie(key,value)
set_cookie可以設置的參數:
- key:鍵
- value:值
- max_age=None,超時時間,cookie需要延續的時間(以秒為單位)如果參數是\None’',這個–cookie會延續到瀏覽器關閉為止
- expires=None,超時時間(IE requires expires,so set it if hasn’t been already.)
- path=‘/’,Cookie生效的路徑,/表示根路徑,特殊的:根路徑的cookie可以被任何url的頁面訪問,瀏覽器只會把cookie回傳給帶有該路徑的頁面,這樣可以避免將cookie傳給站點中的其他的應用。
- domain針對哪個域名有效。默認是針對主域名下都有效,如果只要針對某一個子域名才有效,那么可以設置這個屬性
- secure=False,瀏覽器將通過HTTPS來回傳cookie
- httponly=False,只能http協議傳輸,無法被JavaScript獲取(不是絕對,底層抓包可以獲取到可以被覆蓋)
set_signed_cookie:可以對Cookie的value值進行加鹽
def index(request):response = HttpResponse('Hello World!')response.set_cookie('name','jack')response.set_signed_cookie('sex','man',salt='加鹽')return response
signed_cookie 只是加了簽名的cookie,而不是被加密的cookie,在客戶端還是可以看到沒有加密的value的
注解作用:
單純的記錄uid或者用戶名在cookie中很容易被篡改(也是不建議將用戶敏感信息記錄在cookie中的原因),萬一攻擊者把uid=1換成uid=2豈不是可以訪問uid=2用戶的資源了嗎?而如果換成uid=2r5khk:5Qi0PuFkFQxAFkDnM-UsSljHHxM那么服務端不僅檢驗uid,還檢驗uid=2后面的簽名字段,即是調用HttpRequest.get_signed_cookie(key=key,sait=sait),這樣即使用戶把cookie中的value換成uid=2,但是沒有簽名,服務端照樣拒絕訪問資源。
查詢瀏覽器攜帶的Cookie
當我們響應給客戶端Cookie保存以后,下次客戶端訪問我們的服務端就會攜帶這個Cookie來訪問。
我們可以在視圖接收到客戶端的請求里面提取出Cookie的鍵值對,針對正常設置的Cookie和加鹽的Cookie取值方式有所不同
def index(request):print(request.COOKIES['name']) # 方式一:不推薦使用此方式,如果key不存在則會拋出異常:KeyErrorprint(request.COOKIES.get('name')) # 方式二:獲取name鍵對應的value,如果key不存在則返回Noneprint(request.get_signed_cookie('sex',salt='加鹽')) # 獲取加鹽過的cookie鍵值,salt必須要對上不然報錯return HttpResponse('Hello World!')
刪除Cookie
刪除瀏覽器請求里攜帶的某個Cookie
def index(request):response = HttpResponse('Hello World!')response.delete_cookie('sex')return response
Cookie校驗登錄
通過登錄之后在瀏覽器添加Cookie,只有攜帶該Cookie才能訪問home頁面。
視圖層代碼
from app import models
def login(request,*arg,**kwargs):if request.method == 'POST':username = request.POST.get('username')password = request.POST.get('password')'''查詢數據庫中的用戶數據比對'''obj = models.UserInfo.objects.filter(username=username,password=password).first()if obj:response = HttpResponse('login success!')response.set_cookie('name', username, max_age=30)response.set_cookie('msg','True',max_age=30) # 定義過期時間# 它們分別都在30秒后過期,也就是瀏覽器只有30秒使用這個Cookie的時間,過了30秒以后再次訪問將不能攜帶該Cookiereturn responseelse:return HttpResponse('賬號或密碼錯誤!')return render(request,'login.html')def home(request):try:name = request.COOKIES['name']msg = request.COOKIES['msg']if name and msg == 'True': # 判斷瀏覽器攜帶的Cookie是否合格return render(request,'home.html')return redirect('/login/') # 不合格重定向到登錄頁面except: # 沒有獲取到指定Cookie的話,則說明Cookie過期了,重定向到登錄頁面return redirect('/login/')
進入home頁面是在請求里頭攜帶了服務端在瀏覽器登錄時響應的Cookie,再次將該Cookie發送給服務端才能得到home頁面的響應。
待我們30秒后再次刷新home頁面時,就會被重定向到登錄界面,因為Cookie過期了
如果需要有多個視圖函數需要使用時,這種的每次都需要寫重復的代碼,這樣代碼的重復性就太高了,所以我們可以做一個裝飾器用來存儲這些重復的代碼
'''檢驗用戶登錄的狀態的裝飾器'''
def login_auth(xxx):def inner(request, *args, **kwargs):'''獲取到用戶上一次想要訪問的urlpath_info ----只有路由地址get_full_path ----可以訪問到瀏覽器后攜帶的get參數'''if request.COOKIES.get('name'):return xxx(request,*args, **kwargs)else:return redirect('/login/') # 通過后綴的方式告知跳轉那一個return innerfrom app import models
def login(request):if request.method == 'POST':username = request.POST.get('username')password = request.POST.get('password')'''查詢數據庫中的用戶數據比對'''obj = models.UserInfo.objects.filter(username=username,password=password).first()if obj:response = HttpResponse('login success!')response.set_cookie('name', username, max_age=30)response.set_cookie('msg','True',max_age=30) # 定義過期時間# 它們分別都在30秒后過期,也就是瀏覽器只有30秒使用這個Cookie的時間,過了30秒以后再次訪問將不能攜帶該Cookiereturn responseelse:return HttpResponse('賬號或密碼錯誤!')return render(request,'login.html')@login_out
def func(request):return HttpResponse('from func')def home(request):try:# name = request.COOKIES['name']# msg = request.COOKIES['msg']name = request.COOKIES.get('name')msg = request.COOKIES.get('msg')if name and msg == 'True': # 判斷瀏覽器攜帶的Cookie是否合格return render(request, 'home.html')return redirect('/login/') # 不合格重定向到登錄頁面except: # 沒有獲取到指定Cookie的話,則說明Cookie過期了,重定向到登錄頁面return redirect('/login/')