天天看點

django -- cookie和session

前戲

我們在通路一些網站的時候,如果沒有登入就會跳轉到登入頁面,如果是登入了,才會讓我們通路,那伺服器是怎麼知道我們有沒有登入呢?這就涉及到了Cookie,大家都知道HTTP的特點,無狀态。也就是浏覽器發送到伺服器的每個請求都是沒有關系的。這時候就要給伺服器設定一個Cookie,下次浏覽器請求的時候,攜帶這個Cookie,如果有攜帶,那伺服器就認為是登入的,如果沒有攜帶或錯誤,那浏覽器就跳轉到登入頁面。

什麼是Cookie呢?

Cookie是指一小段資訊,它是伺服器發送出來存儲在浏覽器上的一組組鍵值對,下次通路伺服器時浏覽器會自動攜帶這些鍵值對。Cookie的工作原理是由伺服器産生内容,浏覽器收到請求後儲存在本地,當浏覽器再次通路時,浏覽器會自動帶上Cookie,這樣伺服器就能通過Cookie判斷目前使用者是哪個了

Cookie初識

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="{{ request.get_full_path }}" method="post">
    {% csrf_token %}
    使用者名:
    <input type="text" name="username">
    密碼:
    <input type="text" name="pwd">
    <input type="submit" value="送出">
</form>
</body>
</html>      

login.html

我們寫三個視圖函數,login,home和index

from django.shortcuts import render,redirect,HttpResponse
from appTest01 import models

# Create your views here.


def login(request):
    if request.method == 'POST':
        user = request.POST.get('username')
        password = request.POST.get('pwd')
        if models.Person.objects.filter(name=user, pwd= password):

            return redirect('/index/')
    return render(request,'login.html')

def index(request):
    return HttpResponse('index')

def home(request):
    return HttpResponse('home')      

上面這樣的寫法,我們可以直接通過路徑通路對應的頁面,不需要登入,當然不符合我們的需求,那我們給加上Cookie

from django.shortcuts import render,redirect,HttpResponse
from appTest01 import models

# Create your views here.


def login(request):
    if request.method == 'POST':
        user = request.POST.get('username')
        password = request.POST.get('pwd')
        if models.Person.objects.filter(name=user, pwd= password):
            ret = redirect('/index/')
            ret.set_cookie('is_login','yes')
            return ret

    return render(request,'login.html')

def index(request):
    print(request.COOKIES,type(request.COOKIES))  檢視cookie
    return HttpResponse('index')

def home(request):
    return HttpResponse('home')      

我們使用set_cookie()來設定Cookie,然後我們輸入賬号密碼去登入,檢視cookie

django -- cookie和session
django -- cookie和session

我們可以使用 request.COOKIES來檢視cookie,

request.COOKIES,type(request.COOKIES)      

結果:

{'csrftoken': 'pB5vZxQOwWnvNyw13S0ImpbInxOpnIV0BsAcE31hCHLOP3EIMM8veLpxIlcRBYIg', 'is_login': 'yes'} <class 'dict'>      

既然它是一個字典類型的,我們就可以拿到cookie,然後在進行一個判斷,在來改寫視圖函數

from django.shortcuts import render,redirect,HttpResponse
from appTest01 import models

# Create your views here.


def login(request):
    if request.method == 'POST':
        user = request.POST.get('username')
        password = request.POST.get('pwd')
        if models.Person.objects.filter(name=user, pwd = password):
            ret = redirect('/index/')
            ret.set_cookie('is_login','yes')
            return ret
    return render(request,'login.html')

def index(request):
    if request.COOKIES.get('is_login') == 'yes':  # 擷取我們設定的Cookie
        return HttpResponse('index')
    return redirect('/login/')

def home(request):
    if request.COOKIES.get('is_login') == 'yes':
        return HttpResponse('home')
    return redirect('/login/')      

上面代碼我們就實作了我們的需求,如果登入成功,可以通路index和home頁面,如果沒有登入,則傳回login頁面,那試想一下,以後我們的項目頁面有幾百個,難道要給每個頁面都要寫判斷嗎?這樣肯定是不行的,我們可以用裝飾器來實作這種需求,代碼如下

from django.shortcuts import render, redirect, HttpResponse
from appTest01 import models


# Create your views here.

def login_cookie(f):
    def inner(request, *args, **kwargs):
        if request.COOKIES.get('is_login') == 'yes':  # 擷取我們設定的Cookie,如果通過,執行被裝飾的函數
            res = f(request, *args, **kwargs)
            return res
        return redirect('/login/')

    return inner


def login(request):
    if request.method == 'POST':
        user = request.POST.get('username')
        password = request.POST.get('pwd')
        if models.Person.objects.filter(name=user, pwd=password):
            ret = redirect('/index/')
            ret.set_cookie('is_login', 'yes')
            return ret
    return render(request, 'login.html')


@login_cookie
def index(request):
    return HttpResponse('index')


@login_cookie
def home(request):
    return HttpResponse('home')      

但是這樣又有個問題,如果我們沒有登入通路home頁面,它會跳轉到登入頁面,我們正确登入之後傳回到了index頁面,這肯定不是我們需要的效果,因為我們在login函數裡已經寫死了,登入成功之後傳回的是index頁面,我們來看下京東沒登入時點選“我的京東”是怎樣處理的

django -- cookie和session

我們可以看到,京東在登入頁面後面加了個參數,然後登入成功之後,直接跳轉到後面的那個參數頁面了,那我們在來修改我們的代碼

from django.shortcuts import render, redirect, HttpResponse
from appTest01 import models


# Create your views here.

def login_cookie(f):
    def inner(request, *args, **kwargs):
        current_url = request.path_info  # 擷取位址中?後面的參數
        print('current_url為:', current_url)
        if request.COOKIES.get('is_login') == 'yes':
            res = f(request, *args, **kwargs)
            return res
        return redirect('/login/?returnurl={}'.format(current_url))  # 拼接url路徑

    return inner


def login(request):
    if request.method == 'POST':
        user = request.POST.get('username')
        password = request.POST.get('pwd')
        if models.Person.objects.filter(name=user, pwd=password):
            url_parameter = request.GET.get('returnurl')  # 擷取目前路徑裡的returnurl參數
            ret = redirect(url_parameter)  # 傳回到returnurl頁面
            ret.set_cookie('is_login', 'yes')
            return ret
    return render(request, 'login.html')


@login_cookie
def index(request):
    return HttpResponse('index')


@login_cookie
def home(request):
    return HttpResponse('home')      

結果:

如果你在未登入狀态下通路home頁面,current_url就為/home/
如果你在未登入狀态下通路index頁面,current_url就為/index/      

那麼問題又來了,如果我們直接通路login頁面,登入成功則會報錯,這是因為目前的 url_parameter 參數為空,隻需要修改login函數裡的東西就可以了

def login(request):
    if request.method == 'POST':
        user = request.POST.get('username')
        password = request.POST.get('pwd')
        if models.Person.objects.filter(name=user, pwd=password):
            url_parameter = request.GET.get('returnurl')  # 擷取目前路徑裡的returnurl參數
            if url_parameter:  # 如果有值
                ret = redirect(url_parameter)  # 傳回到returnurl頁面
            else:  # 如果為空
                ret = redirect('/home/')
            ret.set_cookie('is_login', 'yes')
            return ret
    return render(request, 'login.html')      

設定和擷取Cookie

在上面的例子中,我們是使用 set_cookie()來進行設定Cookie,還有另一種方式

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

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

擷取Cookie就不能使用request.COOKIES[’key‘]或者request.COOKIES.get('key')的方法擷取了,要使用如下的方法擷取

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

get_signed_cookie方法的參數:

  • default: 預設值
  • salt: 加密鹽
  • max_age: 背景控制過期時間

删除Cookie

删除Cookie使用delete_cookie('key')

def loginout(request):
    res = redirect('/login/')
    res.delete_cookie('is_login')  # 删除我們設定的is_login的cookie
    return res      

Cookie的其他參數

  1. key,鍵
  2. value='' 值
  3. max_age=xx   逾時時間,xx為一個int型的,機關為秒,如xx=60,則cookie的有效期為60秒
  4. path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie可以被任何url的頁面通路
  5. domain=None, Cookie生效的域名
  6. secure=False, https傳輸
  7. httponly=False 隻能http協定傳輸,無法被JavaScript擷取(不是絕對,底層抓包可以擷取到也可以被覆寫)

 Session

Cookie雖然在一定程度上解決了“保持狀态”的需求,但是由于Cookie本身最大支援4096位元組,以及Cookie本身儲存在用戶端,可能被攔截或竊取,是以就需要有一種新的東西,它能支援更多的位元組,并且他儲存在伺服器,有較高的安全性。這就是Session。

問題來了,基于HTTP協定的無狀态特征,伺服器根本就不知道通路者是“誰”。那麼上述的Cookie就起到橋接的作用。

我們可以給每個用戶端的Cookie配置設定一個唯一的id,這樣使用者在通路時,通過Cookie,伺服器就知道來的人是“誰”。然後我們再根據不同的Cookie的id,在伺服器上儲存一段時間的私密資料,如“賬号密碼”等等。

設定session

我們隻需要把上面設定cookie和設定session的代碼改下11,30,48行就可以了

1 from django.shortcuts import render, redirect, HttpResponse
 2 from appTest01 import models
 3 
 4 
 5 # Create your views here.
 6 
 7 def login_cookie(f):
 8     def inner(request, *args, **kwargs):
 9         current_url = request.path_info  # 擷取位址中?後面的參數
10         print('current_url為:', current_url)
11         # if request.COOKIES.get('is_login') == 'yes':
12         if request.session.get('is_login') == 'yes':  # 擷取session
13             res = f(request, *args, **kwargs)
14             return res
15         return redirect('/login/?returnurl={}'.format(current_url))  # 拼接url路徑
16 
17     return inner
18 
19 
20 def login(request):
21     if request.method == 'POST':
22         user = request.POST.get('username')
23         password = request.POST.get('pwd')
24         if models.Person.objects.filter(name=user, age=password):
25             url_parameter = request.GET.get('returnurl')  # 擷取目前路徑裡的returnurl參數
26             if url_parameter:  # 如果有值
27                 ret = redirect(url_parameter)  # 傳回到returnurl頁面
28             else:  # 如果為空
29                 ret = redirect('/home/')
30             # ret.set_cookie('is_login', 'yes',max_age=5)
31             request.session['is_login']='yes'  # 設定session
32             return ret
33     return render(request, 'login.html')
34 
35 
36 @login_cookie
37 def index(request):
38     return render(request, 'index.html')
39 
40 
41 @login_cookie
42 def home(request):
43     return HttpResponse('home')
44 
45 
46 def loginout(request):
47     res = redirect('/login/')
48     # res.delete_cookie('is_login')  # 删除我們設定的is_login的cookie
49     request.session.delete() # 删除session
50     return res      

session會預設存在django_session這張表裡

django -- cookie和session

你去浏覽器檢視cookie會發現,這時浏覽器儲存的key不在是is_login了,而是sessionid,value也不在是yes了,而是資料庫裡存的session_key,當浏覽器在次發請求時,Django會去django_session表裡查詢有沒有對應的這個value,如果有,則認為登入過

django -- cookie和session

session的其他方法

# 擷取、設定、删除Session中資料
request.session['k1']  # 擷取key,找不到會報錯
request.session.get('k1',None)  # 擷取key,找不到為None
request.session['k1'] = 123 # 設定session
request.session.setdefault('k1',123) # 設定,如果存在k1則不設定
del request.session['k1']  # 删除k1的session


# 所有 鍵、值、鍵值對
request.session.keys()  # 擷取所有的key
request.session.values()  # 擷取所有的value
request.session.items()  # 擷取所有的key和value
request.session.iterkeys()  # 生成器類型的key
request.session.itervalues()  # 生成器類型的value
request.session.iteritems()

# 會話session的key
request.session.session_key  # 擷取資料庫裡存的那個session_key的值

# 将所有Session失效日期小于目前日期的資料删除
request.session.clear_expired()

# 檢查會話session的key在資料庫中是否存在
request.session.exists("session_key")  # 布爾值,存在傳回True

# 删除目前會話的所有Session資料
request.session.delete()  # 浏覽器裡的sessionid還存在,隻是删除了資料庫裡的資料
  
# 删除目前的會話資料并删除會話的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配置

from django.conf import global_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,預設修改之後才儲存(預設)      

 總結:

1. cookie

  1. cookie是什麼?

    儲存在浏覽器上一組組鍵值對

  2. 為什麼要有cookie?

    http協定是無狀态,每次請求都是無關聯的,沒有辦法儲存狀态。

    使用cookie儲存狀态。

  3. django的操作cookie

    3.1. 設定cookie

      ret = HttpResponse('xxx')

      ret.set_cookie(key,value,max_age=5)

      ret.set_signed_cookie(key,value,max_age=5,salt='xxx')

    3.2. 擷取cookie

      request.COOKIES['is_login']

      request.COOKIES.get('is_login')

      request.get_signed_cookie(key,salt='xxx',default='')

    3.3. 删除cookie

      ret.delete_cookie(key)

2. session

  1. session是什麼?

    儲存在伺服器上一組組鍵值對,依賴cookie

  2. 為什麼要用session?

    2.1. cookie儲存在浏覽器上 不安全

    2.2. cookie的長度受到限制

  3. django中操作session

    3.1. 設定session

      request.session[key] = value

      request.session.setdefault(key,value)

    3.2. 擷取session

      request.session[key]

      request.session.get(key)

    3.3. 删除session

      del request.session[key] ——》删除某一個鍵值對

      request.session.delete() ——》 删除該使用者的所有的session資料,不删除cookie

      request.session.flush() ——》 删除該使用者的所有的session資料,删除cookie

  4. 設定逾時時間

    request.session.set_expiry()

  5. 清除所有過期的session

    request.session.clear_expired()

轉載于:https://www.cnblogs.com/zouzou-busy/p/11241155.html