cookie和session在Django中的應用

1 會話跟蹤技術

什麼是會話跟蹤

咱們須要先了解一下什麼是會話!能夠把會話理解爲客戶端與服務器之間的一次會晤,在一次會晤中可能會包含屢次請求和響應。例如你給10086打個電話,你就是客戶端,而10086服務人員就是服務器了。從雙方接通電話那一刻起,會話就開始了,到某一方掛斷電話表示會話結束。在通話過程當中,你會向10086發出多個請求,那麼這多個請求都在一個會話中。 
在Web中,客戶向某一服務器發出第一個請求開始,會話就開始了,直到客戶關閉了瀏覽器會話結束。 

在一個會話的多個請求中共享數據,這就是會話跟蹤技術。例如在一個會話中的請求以下:  請求銀行主頁; html

 

  • 請求登陸(請求參數是用戶名和密碼);
  • 請求轉帳(請求參數與轉帳相關的數據); 
  • 請求信譽卡還款(請求參數與還款相關的數據)。  

在這上會話中當前用戶信息必須在這個會話中共享的,由於登陸的是張三,那麼在轉帳和還款時必定是相對張三的轉帳和還款!這就說明咱們必須在一個會話過程當中有共享數據的能力。python

會話路徑技術使用Cookie或session完成

咱們知道HTTP協議是無狀態協議,也就是說每一個請求都是獨立的!沒法記錄前一次請求的狀態。但HTTP協議中可使用Cookie來完成會話跟蹤!在Web開發中,使用session來完成會話跟蹤,session底層依賴Cookie技術。sql

2 cookie介紹

cookie的由來

你們都知道HTTP協議是無狀態的。數據庫

無狀態的意思是每次請求都是獨立的,它的執行狀況和結果與前面的請求和以後的請求都無直接關係,它不會受前面的請求響應狀況直接影響,也不會直接影響後面的請求響應狀況。django

一句有意思的話來描述就是人生只如初見,對服務器來講,每次的請求都是全新的。後端

狀態能夠理解爲客戶端和服務器在某次會話中產生的數據,那無狀態的就覺得這些數據不會被保留。會話中產生的數據又是咱們須要保存的,也就是說要「保持狀態」。所以Cookie就是在這樣一個場景下誕生。瀏覽器

什麼是cookie

其實Cookie是key-value結構,相似於一個python中的字典。隨着服務器端的響應發送給客戶端瀏覽器。而後客戶端瀏覽器會把Cookie保存起來,當下一次再訪問服務器時把Cookie再發送給服務器。 Cookie是由服務器建立,而後經過響應發送給客戶端的一個鍵值對。客戶端會保存Cookie,並會標註出Cookie的來源(哪一個服務器的Cookie)。當客戶端向服務器發出請求時會把全部這個服務器Cookie包含在請求中發送給服務器,這樣服務器就能夠識別客戶端了!緩存

cookie的原理

cookie的工做原理是:由服務器產生內容,瀏覽器收到請求後保存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上Cookie,這樣服務器就能經過Cookie的內容來判斷這個是「誰」了。安全

Cookie規範 

  •  Cookie大小上限爲4KB; 
  •  一個服務器最多在客戶端瀏覽器上保存20個Cookie; 
  •  一個瀏覽器最多保存300個Cookie;  

上面的數據只是HTTP的Cookie規範,但在瀏覽器大戰的今天,一些瀏覽器爲了戰勝對手,爲了展示本身的能力起見,可能對Cookie規範「擴展」了一些,例如每一個Cookie的大小爲8KB,最多可保存500個Cookie等!但也不會出現把你硬盤佔滿的可能! 
注意,不一樣瀏覽器之間是不共享Cookie的。也就是說在你使用IE訪問服務器時,服務器會把Cookie發給IE,而後由IE保存起來,當你在使用FireFox訪問服務器時,不可能把IE保存的Cookie發送給服務器。服務器

Cookie的覆蓋 

  若是服務器端發送重複的Cookie那麼會覆蓋原有的Cookie,例如客戶端的第一個請求服務器端發送的Cookie是:Set-Cookie: a=A;第二請求服務器端發送的是:Set-Cookie: a=AA,那麼客戶端只留下一個Cookie,即:a=AA。

在瀏覽器中查看cookie

瀏覽器中按F12,點network---cookies就能看到

Django中操做Cookie

獲取Cookie

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)

參數:

  • default: 默認值
  • salt: 加密鹽
  • max_age: 後臺控制過時時間

設置Cookie

rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value)
rep.set_signed_cookie(key,value,salt='加密鹽')

參數:

  • 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=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獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)

刪除Cookie

def logout(request):
    rep = redirect("/login/")
    rep.delete_cookie("user")  # 刪除用戶瀏覽器上以前設置的usercookie值
    return rep

Cookie版登陸校驗

views視圖代碼

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()    #獲取請求的全路徑
        # /shopping/?nana=ppp
        is_login = request.COOKIES.get('is_login')    #服務端先拿到cookie,若是拿到則直接跳轉到shopping或者order視圖頁面
        # xxx=request.get_signed_cookie('xxx',salt='123')
        # print(xxx)
        if is_login:           #拿到cookie判斷是否是登錄狀態
            ret = func(request,*args, **kwargs)   #是登錄狀態直接調用被裝飾的函數,返回咱們想要的頁面
        else: return redirect('/login/?next=%s' % url)   #服務端若是拿不到正確的cookie就會重定向了login這個頁面,可是帶了一些參數
        # 當清空瀏覽器緩存是直接登錄http://127.0.0.1:8000/shopping/,會跳轉到登錄頁面,並在url後面拼上http://127.0.0.1:8000/login/?next=/shopping/
        # 127.0.0.1:8000/login/?next=/shopping/?nana=ppp
        return ret return inner def login(request): if request.method == 'POST': # url = request.GET.get('next') #裝飾器中redirect('/login/?next=%s' % url) ,經過get就能夠拿到next的值
        name = request.POST.get('name') pwd = request.POST.get('pwd') if name == 'lqz' and pwd == '123': # obj = redirect(url) #登陸成功後跳轉到該頁面
            obj=HttpResponse('登陸成功') obj.set_cookie('is_login', True)   #當咱們不指定path時,被裝飾的視圖函數頁面只要登錄後均可以直接被訪問,而不須要從新登錄
            # obj.set_cookie('is_login', True,path='/shopping/') #瀏覽器只會把cookie回傳給帶有該路徑的頁面,也就是說當咱們登路成功後,訪問shopping頁面時能夠直接登錄
            #可是咱們訪問order頁面時,任然會跳到登錄頁面讓咱們從新登錄
            import datetime now = datetime.datetime.now().strftime('%Y-%m-%d %X') obj.set_cookie('last_time', now)    #設置cookie,在瀏覽器的請求頭中的cookie中咱們能夠看到咱們設置的cookie,並將登錄時間也寫到cookie中
            obj.set_cookie('name', 'lqz')   #在瀏覽器中打開能夠看到是一個key
            obj.set_cookie('pwd', '123')   #             obj.set_signed_cookie('xxx','xxxxxx',salt='123')   #獲取cookie,並對cookie進行加鹽,加鹽後的123是進過加密的一串字符碼
            return obj    #登陸成功後對其進行重定向
        else: obj = HttpResponse('登錄失敗') return obj return render(request, 'login.html') # 退出登陸
def logout(request): obj=HttpResponse('註銷成功') obj.delete_cookie('is_login')     #登錄成功得到服務端發送來的cookie,刪除cookie,這樣咱們在瀏覽器中再輸入http://127.0.0.1:8000/shopping/
    return obj                         #就會再次跳到登錄頁面讓咱們進行從新登錄

# 購物頁面
@login_auth def shopping(request): return render(request, 'shopping.html', locals()) #.locals()用法:locals()能夠直接將函數中全部的變量所有傳給模板。固然這可能會傳遞一些多餘的參數,有點浪費內存的嫌疑
    # 登錄成功後在請求shopping頁面,在在請求頭中就能夠看到請求頭中的cookie中帶有(鍵值對的形式):
    # Cookie: csrftoken = ybQexReWXIWaO0If0p0I7NubfBSvjUlSfR2EWWX8eKCwXbL8lDo4Kk3ar6Nbr5ZR;
    # last_time = "2018-09-13 18:13:17";
    # name = lqz;
    # pwd = 123;
    # xxx = xxxxxx:1g0Ocf: 1kRB9Q0FVXlVzstrRbm4fJ61eF0 # 訂單頁面
@login_auth def order(request): return render(request, 'order.html', locals())
views

template模板代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
    <p>用戶名:<input type="text" name="name"></p>
    <p>密碼:<input type="password" name="pwd"></p>
    <input type="submit">
    
</form>
</body>
</html>
login
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>購物車頁面</h2>

</body>
</html>
shopping
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<h1>訂單頁面</h1>

</body>
</html>
order

urls路由配置

from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.login), url(r'^order/', views.order), url(r'^shopping/', views.shopping), url(r'^logout/', views.logout), ]
urls

會話Session

由於因特網HTTP協議的特性,每一次來自於用戶瀏覽器的請求(request)都是無狀態的、獨立的。通俗地說,就是沒法保存用戶狀態,後臺服務器根本就不知道當前請求和之前及之後請求是否來自同一用戶。對於靜態網站,這可能不是個問題,而對於動態網站,尤爲是京東、天貓、銀行等購物或金融網站,沒法識別用戶並保持用戶狀態是致命的,根本就沒法提供服務。你能夠嘗試將瀏覽器的cookie功能關閉,你會發現將沒法在京東登陸和購物。

爲了保持鏈接狀態,網站會經過用戶的瀏覽器在用戶機器內被限定的硬盤位置中寫入一些數據,也就是所謂的Cookie。經過Cookie能夠保存一些諸如用戶名、瀏覽記錄、表單記錄、登陸和註銷等各類數據。可是這種方式很是不安全,由於Cookie保存在用戶的機器上,若是Cookie被僞造、篡改或刪除,就會形成極大的安全威脅,所以,現代網站設計一般將Cookie用來保存一些不重要的內容,實際的用戶數據和狀態仍是以Session會話的方式保存在服務器端。

Session就是在服務器端的‘Cookie’,將用戶數據保存在服務器端,遠比保存在用戶端要安全、方便和快捷得多。

Session依賴Cookie!但與Cookie不一樣的地方在於Session將全部的數據都放在服務器端,用戶瀏覽器的Cookie中只會保存一個非明文的識別信息,好比哈希值。

Session是大多數網站都須要具有的功能。Django爲咱們提供了一個通用的Session框架,而且可使用多種session數據的保存方式:

  • 保存在數據庫內
  • 保存到緩存
  • 保存到文件內
  • 保存到cookie內

一般狀況,沒有特別需求的話,請使用保存在數據庫內的方式,儘可能不要保存到Cookie內。

Django的session框架支持匿名會話,封裝了cookies的發送和接收過程。cookie包含一個會話ID而不是數據自己(除非你使用的是基於後端的cookie)。

Django的會話框架徹底地、惟一地基於Cookie。它不像PHP同樣,把會話的ID放在URL中。那樣不只使得URL變得醜陋,還使得你的網站易於受到經過"Referer"頭部進行竊取會話ID的攻擊。

django中的session相關用法

# 獲取、設置、刪除Session中數據
request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在則不設置
del request.session['k1'] # 全部 鍵、值、鍵值對
request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 會話session的key
request.session.session_key # 將全部Session失效日期小於當前日期的數據刪除
request.session.clear_expired() # 檢查會話session的key在數據庫中是否存在
request.session.exists("session_key") # 刪除當前會話的全部Session數據
request.session.delete()    # 刪除當前的會話數據並刪除會話的Cookie。
request.session.flush() 這用於確保前面的會話數據不能夠再次被用戶的瀏覽器訪問 例如,django.contrib.auth.logout() 函數中就會調用它。 # 設置會話Session和Cookie的超時時間
request.session.set_expiry(value) * 若是value是個整數,session會在些秒數後失效。 * 若是value是個datatime或timedelta,session就會在這個時間後失效。 * 若是value是0,用戶關閉瀏覽器session就會失效。 * 若是value是None,session會依賴全局session失效策略。

在視圖中使用session

def session_test(request): # 設置session值,會將其存到db.sqlite數據庫中的django_session表中,每發送一次請求就會在django_sesssion表中添加一條記錄
    request.session['username']='lqz'      #     request.session['is_login']=True ''' 1 生成一個隨機字符串 2 把隨機字符串以cookie的形式寫回給瀏覽器 3 會在數據庫裏存{'隨機字符串':{'username':'lqz','is_login':True}} '''

    return HttpResponse('ok') def get_session(request): # 在瀏覽器中輸入路由地址就會訪問訪問該視圖函數,獲取session值,可是必定要先獲取session值
    #不然獲取session時會報錯
    # name=request.session['username']
    # is_login=request.session['is_login']
    # print(name)
    # print(is_login)
    # session取值的兩種方式,字典key或者get進行取值
    # request.session['k1']
    # request.session.get('k1', None)
    # 設置session的值
    # request.session['k1'] = 123

    # name=request.session.setdefault('username', 123) # 若是session中的username有值就不會設置,無值則進行設置
    # print(name) #-----123
    # del request.session['k1'] #經過key將session的值進行刪除
    # print(request.session.session_key) #取出表django_session表中session_key字段對應的值
    # 將全部Session失效日期小於當前日期的數據刪除
    # request.session.clear_expired()
    # 判斷session表中session_key字段的值是否存在,返回值爲布爾值
    # print(request.session.exists("b16mh23xajc2u69vazvivf8ruo4ilumi"))
    # 會刪除數據庫的session表中的session的記錄,可是瀏覽器中的session id還在
    # request.session.delete()
    # 刪除當前的會話數據並刪除會話的Cookie。
    # 一般用它,他會把數據庫以及瀏覽器會話中的session id都刪除(調用視圖函數test能夠看到效果的確是已經被刪除)
 request.session.flush() return HttpResponse('ok') def test(request): return HttpResponse('ok')

在視圖函數中使用裝飾器裝飾CBV

from django.utils.decorators import method_decorator # 在視圖中裝飾類須要先將該模塊先導入,method_decorator
from django.views import View # @method_decorator(login_auth,name='post') # @method_decorator(login_auth,name='get') # 在類上加裝飾器須要指定name的值,也就是要指定裝飾類內的哪一個函數,當咱們登錄成功後就會直接跳轉到咱們要登錄的頁面
class MyOrder(View): # @method_decorator(login_auth) #將裝飾器出傳入進去
    def dispatch(self, request, *args, **kwargs): # 咱們能夠重寫dispatch函數來實現相似裝飾器的效果,dispatch內部根據反射來實現函數執行。
        ret=super().dispatch(request, *args, **kwargs)   #繼承父類View的屬性
        return ret # 在cbv上加裝飾器,須要用method_decorator修飾一下
 @method_decorator(login_auth) def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post') ''' 1 導入from django.utils.decorators import method_decorator 2 加載get,post,dispatch方法上:@method_decorator(login_auth) 3 加在類上:@method_decorator(login_auth,name='get') '''
相關文章
相關標籤/搜索