cookie和session的那些事

對於常常網購的朋友來講,常常會遇到一種狀況:
打開淘寶或京東商城的首頁,輸入我的帳號和密碼進行登錄,而後進行購物,支付等操做都不須要用戶再次輸入用戶名和密碼
可是若是用戶換一個瀏覽器或者等幾個小時後再刷新這些網頁進行購物操做,就必需要再次輸入用戶名和密碼了.html

這是爲何呢??這就用到了cookiesession的知識了.python

1. cookie的簡介

一、http是無狀態協議,cookie不屬於http協議範圍.

在實際應用中,服務端與客戶端須要保持鏈接狀態,此時就須要使用到cookie.web

cookie的工做原理是:由服務器產生客戶端身份信息發送給客戶端,客戶端收到信息後保存在本地;
當客戶端瀏覽器再次訪問服務端時,會自動帶上這段身份信息,服務器經過這段信息來判斷客戶端的身份。chrome

打開chrome瀏覽器,在地址欄裏輸入www.cnblogs.com,回車在檢查中能夠的信息以下圖所示:數據庫

其中,能夠看到這次的請求頭(Request Headers):django

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:__gads=ID=ec125291e23201fe:T=1504664243:S=ALNI_MZTHHsRs1K2HAD8kB_Q7zN777zCMA
Host:www.cnblogs.com
If-Modified-Since:Sat, 09 Sep 2017 12:38:59 GMT
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36

在這些信息裏,能夠看到cookie信息是包含在請求頭裏的.
瀏覽器發請求的時候,會從瀏覽器中取出cookie附加到請求頭上,給服務端發過去.服務端接收到客戶端的cookie以後,會給客戶端返回相應的信息.後端

還能夠看到服務端的響應頭(Response Headers):瀏覽器

Cache-Control:public, max-age=19
Connection:keep-alive
Content-Encoding:gzip
Content-Type:text/html; charset=utf-8 
Date:Sat, 09 Sep 2017 12:42:16 GMT
Expires:Sat, 09 Sep 2017 12:42:36 GMT
Last-Modified:Sat, 09 Sep 2017 12:42:06 GMT
Transfer-Encoding:chunked
Vary:Accept-Encoding
X-Frame-Options:SAMEORIGIN
X-UA-Compatible:IE=10

二、cookie在必定程度上解決了"保持狀態"的需求

因爲cookie自己最大支持4096字節,而且cookie保存在客戶端,可能被攔截或竊取,
所以須要有一種新的東西,它來彌補cookie的一些缺陷,而且保存在服務端,有較高的安全性,這就是session。安全

基於http協議的無狀態特徵,服務器不知道訪問者的身份,此時cookie就起到橋接的做用。服務器

服務端給每一個客戶端的cookie分配一個惟一的隨機id,用戶在訪問服務端時,服務器經過cookie來判斷客戶端的身份。

服務端根據cookie的id的不一樣,在必定的期限內保存客戶端傳送過來的帳號密碼等關鍵信息.

三、cookie彌補了http無狀態的不足,讓服務器可以判斷客戶端的身份;

cookie以文本的形式保存在本地,自身安全性較差,所以服務端經過cookie識別不一樣的用戶,對應的在session裏保存私密的信息以及超過4096字節的文本。

四、cookie和session實際上是共通性的東西,不限於語言和框架

2.cookie和session的工做機制

每當咱們使用一款瀏覽器訪問一個登錄頁面的時候,一旦咱們經過了認證,服務器端就會發送一組隨機惟一的字符串(假設是123abc)到瀏覽器端.
這個被存儲在瀏覽器端的東西就叫cookie。而服務器端也會存儲一下用戶當前的狀態,好比login=trueusername="name"之類的用戶信息。
這種信息是以字典形式存儲成爲一個字符串,這串字符串以用戶第一次請求時獲得的cookie值爲鍵,這就是session.

那麼若是在服務器端查看session信息的話,理論上就會看到以下樣子的相似的字典
{'123abc':{'login':true,'username':'hahaha'}}

由於每一個cookie都是惟一隨機的,因此咱們在同一臺電腦上換個瀏覽器再登錄同一個網站也須要再次驗證。

那麼爲何說咱們只是理論上看到這樣子相似的字典呢?由於處於安全性的考慮,其鍵和值在服務器端都會被加密。

因此咱們服務器上就算打開session信息看到的也是相似與如下樣子的東西:

{'123abc':dasdasdasd1231231da1231231}

3.cookie和session的初步使用

例子:製做一個登錄頁面,服務端使用cookie和session驗證了用戶名和密碼後才能跳轉到後臺的頁面。

3.1 首先建立一個Django的項目,配置好urls和settings,templates中建立一個login.html和index.html頁面

views中的代碼:

def index(request):
    return render(request,"index.html")

def login(request):
    print("cookie:",request.COOKIES)#打印cookie信息
    if request.method=="POST":#若是瀏覽器使用post方式提交信息
        name=request.POST.get("username")
        pwd=request.POST.get("password")
        if name=="hello" and pwd=="123456":
            return redirect("/index/")

    return render(request,"login.html")

login頁面:

<form action="/login/" method="post">
    <p>姓名<input type="text" name="username"></p>
    <p>密碼<input type="password" name="password"></p>
    <p><input type="submit"></p>
</form>

index頁面:

<h3>welcome to index page</h3>

打開瀏覽器,輸入http://127.0.0.1:8000/login/打開login頁面,輸入正確的用戶名和密碼,進入index頁面
此時能夠在後端看到以下的cookie信息

cookie: {'csrftoken': 'AdkajMM65wOqa0NONe6dVwYqphGNDOgMbuzstmAy92HJ3GxRWUNpqXKJFXBv1Rn5', 
'sessionid': '7jfj6uqbz6vylplfv429bhfdxh14iwfp'}

其中sessionid中的信息就是Django分配給瀏覽器的一段隨機字符串.

3.2 由用戶本身設置cookie信息

修改login視圖函數:

def login(request):
    print("cookie:",request.COOKIES)
    if request.method=="POST":
        name=request.POST.get("username")
        pwd=request.POST.get("password")
        if name=="hello" and pwd=="123456":
            res=redirect("/index/")
            res.set_cookie("login_message","hello python")#設置cookie信息
            return res
    return render(request,"login.html")

而後重啓應用,從新輸入用戶名和密碼,進入index頁面,此時能夠看到以下的cookie信息:

cookie: {'csrftoken': 'AdkajMM65wOqa0NONe6dVwYqphGNDOgMbuzstmAy92HJ3GxRWUNpqXKJFXBv1Rn5', 
'sessionid': '7jfj6uqbz6vylplfv429bhfdxh14iwfp', 'login_message': 'hello python'}

能夠看到在後端的login視圖函數中設置的cookie的鍵值對,瀏覽器請求後又會被服務端接收.

用戶請求頁面時,是帶着標示本身的身份信息的,服務端對客戶端的身份信息進行判斷,只有身份正確,才能進入index頁面.
可是若是在瀏覽器的地址中直接輸入index的路由地址,也能進入index的頁面的狀況,這不符合咱們的要求.

3.3 實現客戶端沒有cookie,即便用戶輸入index路由信息,服務端發送登陸頁面給用戶

若是客戶端沒有cookie,說明用戶名或密碼沒有驗證成功,服務端就會把login頁面發送給客戶端瀏覽器,
只有用戶輸入正確的用戶名和密碼,服務端纔會把index頁面發送給客戶端瀏覽器.

修改index視圖函數:

def index(request):
    if request.COOKIES.get("login_message")=="hello python":
        return render(request,"index.html",locals())
    else:
        return redirect("/login/")

這樣用戶在一個瀏覽器中通過驗證進入index.html頁面後,清除cookie或者更換一個瀏覽器再想進入index頁面,就要再次驗證用戶名和密碼了.

因爲用戶的cookie信息保存在客戶端,每與服務端通訊一次,客戶端就要把cookie信息發送經服務端一次,並且保存在客戶端也不夠安全,因此又出現了session
session也保存客戶端身份的信息,用戶登陸後服務端把表示用戶身份的信息保存成以鍵值對形式存在的session中,而後服務端把這個字典發送給客戶端的cookie,

這時客戶端的cookie就以一個字符串的形式存在.

客戶端使用cookie和session與服務端進行通訊的步驟:

用戶通過用戶名和密碼驗證登錄後,生成一個字典,將字典存入session,session的key是自動生成一段字符串標識,也就是前面說過的cookie.
服務端返回給客戶端session,session的value存儲了用戶的關鍵信息,如user和iflogin等.

在Django中用到session時,cookie由服務端隨機生成,寫到瀏覽器的cookie中,每一個瀏覽器都有本身的cookie值,是session尋找用戶信息的惟一標識

每一個瀏覽器請求到後臺接收的request,這時的session等價於標識用戶身份信息的字典

3.4 使用cookie加session來完成上面的例子

修改views中的login視圖函數

def login(request):
    print("cookie:",request.COOKIES)
    print("session:",request.session)

    if request.method=="POST":
        name=request.POST.get("username")
        pwd=request.POST.get("password")
        if name=="hello" and pwd=="123456":

            res=redirect("/index/")
            res.set_cookie("login_message","hello python")
            return res

    return render(request,"login.html")

再次刷新瀏覽器,輸入正確的用戶名和密碼後,打印cookie和session:

cookie: {'csrftoken': 'AdkajMM65wOqa0NONe6dVwYqphGNDOgMbuzstmAy92HJ3GxRWUNpqXKJFXBv1Rn5', 
'sessionid': '7jfj6uqbz6vylplfv429bhfdxh14iwfp', 'login_message': 'hello python'}

session: <django.contrib.sessions.backends.db.SessionStore object at 0x00000000043D7D30>

能夠看到的是此時的session是一個對象.

知道了cookie和session的狀況後,那麼該怎麼使用cookie和session呢

修改視圖函數

def index(request):
    if request.session.get("is_login",None):#獲取session中用戶登陸的信息
        name=request.session.get("user")#獲取session中的用戶名
        return render(request,"index.html",locals())
    else:
        return redirect("/login/")

def login(request):
    print("cookie:",request.COOKIES)
    print("session:",request.session)

    if request.method=="POST":
        name=request.POST.get("username")
        pwd=request.POST.get("password")
        
        if name=="hello" and pwd=="123456":
            request.session["is_login"]=True
            request.session["user"]=name
            return redirect("/index/")
    return render(request,"login.html")

先使用

python manage.py makemigrations
python manage.py migrate

命令初始化數據庫,
而後在瀏覽器中輸入http://127.0.0.1:8000/index/後,直接進入登陸頁面了,輸入正確的用戶名和密碼,後端會打印以下信息:

cookie: {}
session: <django.contrib.sessions.backends.db.SessionStore object at 0x00000000043B46D8>

4 cookie和session的用法:

4.1 操做cookie

獲取cookie            request.COOKIE[key]
設置cookie            response.set_cookie(key,value)

因爲cookie保存在客戶端的電腦上,因此jQuery也能夠操做cookie

在上面的例子中,在html頁面中就使用Django的語法能夠渲染name變量.

設置cookie的失效時間:

import datetime#導入datetime模塊

response.set_cookie("username",{"11":"22"},max_age=10,
    expires=datetime.datetime.utcnow()+datetime.timedelta(days=3))

其中:

datetime.datetime.utcnow()表示當前時間
datetime.timedelta(days=3)表示3天

上面的代碼表示設置cookie在當前時間的3天后失效

4.2 操做session(session默認在服務端保存15天)

獲取session       request.session[key]或者request.session.get(key)
設置session       request.session[key]=value
刪除session       del request.session[key]

須要注意的是,刪除服務端的session不會刪除數據庫中的session_data,而只是把session更新爲一個其餘的值

設置session的失效時間:

request.session.set_expiry(value)是設置session的失效時間

參數說明:

若是value是一個整數,session會在整數稱後失效
若是value是個datatime或者timedelta,session會在這個時間以後失效
若是value是0,用戶關閉瀏覽器後session就會失效
若是value是None,session會依賴全局session的失效策略
相關文章
相關標籤/搜索