1. 程式人生 > >Django - cookie 、session

Django - cookie 、session

目錄

一、cookie、session - 概念

1-1 cookie - 儲存在瀏覽器的key-value結構資料

1-1-1 cookie 原理

1-1-2 cookie 規範

1-1-3 cookie的覆蓋 - 伺服器端傳送重複的Cookie那麼會覆蓋原有的Cookie

1-2 Session - 儲存在伺服器的key-value結構資料

二、 Django中操作cookie

2-1 獲取cookie

2-2 設定cookie

 2-3 刪除cookie

三、cookie 實現登陸校驗

四、Django操作Session

4-1 set、get練習

 五、Django中的Session配置 - 可放置於快取、redis(記憶體資料庫)等資料庫、settings檔案等 -- 可以同時配置多個區域

六、session -  實現登陸校驗

6-1 基於CBV + 裝飾器 實現登入驗證


一、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-確認登陸,可進行購物操作')