day13 cookie與session和中介軟體

迷戀~以成傷發表於2021-12-08

day13 cookie與session和中介軟體

今日內容概要

  • cookie與session簡介
  • django操作cookie與session
  • django中介軟體簡介
  • 如何自定義中介軟體
  • csrf跨站請求偽造(釣魚網站)
  • csrf相關操作

cookie與session簡介

http協議
	四大特性
    	1.基於請求響應
        2.基於TCP\IP作用於應用層之上
        3.無狀態
        	基於http協議通訊的服務端無法儲存客戶端狀態
            	縱使見她千百遍 我都當她如初見
        4.無(短)連線
        
隨著網際網路的發展 很多網站都需要儲存客戶端狀態 為了實現該需求
# cookie與session應運而生(最初的功能核心:儲存使用者狀態)
    cookie:服務端讓客戶端瀏覽器儲存的資料(kv鍵值對)
    session:服務端儲存的關於使用者相關的資料(kv鍵值對)
    '''session的工作需要依賴於cookie'''
    
# 目前只要是需要使用者登入的網站 基本都需要使用cookie
	客戶端瀏覽器也可以拒絕儲存cookie

django操作cookie

# 檢視函式必須返回HttpResponse物件
    from django.shortcuts import HttpResponse,render,redirect
    return HttpResponse()
    return render()
    return redirect()

# 要想操作cookie必須先產生物件,之後利用物件內建方法操作
    obj1 = HttpResponse()
    return obj1
    obj2 = render()
    return obj2
    obj3 = redirect()
    return obj3

# 設定與獲取cookie
    obj.set_cookie()  # 讓瀏覽器儲存cookie資料
    request.COOKIES.get()  # 獲取瀏覽器攜帶過來的cookie資料
    obj.set_cookie(max_age\expires)  # 以秒為基準
    obj.delete_cookie()

# 獲取當前使用者想要訪問的地址
        request.path_info         # 僅獲取url的字尾名
        request.get_full_path()   # 獲取的全路徑,包含問號後面的引數部分

程式碼練習

from django.shortcuts import render, HttpResponse, redirect


# Create your views here.
from functools import wraps
# 校驗登入裝飾器
def login_auth(func):
    @wraps(func)  # 裝飾器修復技術
    def inner(request, *args, **kwargs):
        # 給引數賦值獲取訪問之前頁面的資料
        target_url = request.path_info
        # 先校驗使用者的cookie
        cookie_data = request.COOKIES.get('name')
        if cookie_data == 'meng':
            res = func(request, *args, **kwargs)
            return res
        else:
            # 加上target_url可以獲取登入之前訪問的頁面
            return redirect('/login/?target_url=%s' % target_url)
    return inner


@login_auth
def home(request):
    return HttpResponse('登入頁面該展示的內容')


@login_auth
def index(request):
    return HttpResponse('index頁面,登入頁面該展示的內容')


@login_auth
def func(request):
    return HttpResponse('func頁面,登入頁面該展示的內容')


def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'meng' and password == '123':
            # 先獲取使用者登入之前需要訪問的頁面,如果沒有資料跳轉到首頁
            target_url = request.GET.get('target_url', '/home/')  # 如果前面沒有資料,使用後面的資料
            obj = redirect(target_url)
            # 設定cookie 
            obj.set_cookie('name', 'meng',expires=3)  # expires:設定幾秒丟掉cookie
            # 跳轉到首頁
            return obj
    return render(request, 'login.html')

# 退出
def logout(request):
    obj = redirect('/home/')
    obj.delete_cookie('name')
    return obj

django操作session

request.session[key] = value  # 設定session
    1.django自動產生一個隨機字串
    2.預設在django_session表中儲存隨機字串與資料的對應關係
    3.將隨機字串傳送給客戶端瀏覽器儲存
    	sessionid:隨機字串

request.session.get(key)  # 獲取session
    1.django自動獲取瀏覽器傳送過來的cookie資料 獲取隨機字串 
    2.拿著隨機字串去django_session表中比對
    3.如果對應上了則獲取資料並解密成明文的形式

'''
需要記住的:
	1.django預設的session失效時間>>>:兩週(14天)
	2.同一個計算機上一個瀏覽器只會有一條資料生效,當session過期的時候可能會出現多條
	還有可能是不同瀏覽器訪問,也可能出現多條資料。
'''

# 刪除當前會話的所有Session資料
    request.session.delete()  # 只刪除瀏覽器資料,客戶端不會刪除
  
# 刪除當前的會話資料並刪除會話的Cookie。
    request.session.flush()   # 推薦使用
    這用於確保前面的會話資料不可以再次被使用者的瀏覽器訪問

# 設定會話Session和Cookie的超時時間
request.session.set_expiry(value)
    * 如果value是個整數,session會在些秒數後失效。
    * 如果value是個datatime或timedelta,session就會在這個時間後失效。
    * 如果value是0,使用者關閉瀏覽器session就會失效。
    * 如果value是None,session會依賴全域性session失效策略。
   
# session的儲存位置是可以自定義的
	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流程解析

django中介軟體

django中介軟體類似於django的門戶 請求來和走都必須經過它
'''
當我們需要給web後端新增一些全域性相關的功能時可以使用中介軟體
	1.校驗每個使用者的訪問頻率
	2.校驗每個使用者的登入狀態
	3.使用者黑名單、白名單
	4.使用者許可權
	...
'''
django預設有七個中介軟體 並且還支援使用者自定義中介軟體
自定義中介軟體我們可以編寫五個方法
	必須掌握的方法
		# process_request(self,request)
        
        	1.當請求來的時候會從上往下依次執行每一箇中介軟體裡面的該方法
            如果沒有則直接下一個
            2.當該方法返回了HttpResponse物件 那麼請求不再繼續往後執行
            而是直接原路返回
            
         # process_response(self,request,response)
        	1.當響應返回的時候會從下往上依次執行每一箇中介軟體裡面的該方法
            如果沒有則直接下一個 該方法預設要返回response
            2.該方法返回什麼瀏覽器就會接收到什麼(也就意味著我們可以中途攔截待返回的資料做其他處理)
         # process_request方法如果直接返回HttpResonse物件則直接執行process_response原理返回
        
	需要了解的方法
    	process_view
        	路由匹配成功之後執行檢視函式之前自動觸發
            
        process_template_response
        	當返回的物件中含有render屬性自動觸發
            
        process_exception
        	當檢視函式報錯之後會自動觸發

中介軟體簡介

什麼是中介軟體?
    官方的說法:中介軟體是一個用來處理Django的請求和響應的框架級別的鉤子。它是一個輕量、低階別的外掛系統,用於在全域性範圍內改變Django的輸入和輸出。每個中介軟體元件都負責做一些特定的功能。

    但是由於其影響的是全域性,所以需要謹慎使用,使用不當會影響效能。

    說的直白一點中介軟體是幫助我們在檢視函式執行之前和執行之後都可以做一些額外的操作,它本質上就是一個自定義類,類中定義了幾個方法,Django框架會在請求的特定的時間去執行這些方法。

    我們一直都在使用中介軟體,只是沒有注意到而已,開啟Django專案的Settings.py檔案,看到下圖的MIDDLEWARE配置項。
    
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

自定義中介軟體

中介軟體可以定義五個方法,分別是:(主要的是process_request和process_response)
必須掌握的方法:
	process_request(self,request)
	process_response(self, request, response)
    
需要了解的方法:
    process_view(self, request, view_func, view_args, view_kwargs)
    process_template_response(self,request,response)
    process_exception(self, request, exception)
    
    以上方法的返回值可以是None或一個HttpResponse物件,如果是None,則繼續按照django定義的規則向後繼續執行,如果是HttpResponse物件,則直接將該物件返回給使用者。

自定義一箇中介軟體例項

process_request

# 我們來看看多箇中介軟體時,Django是如何執行其中的process_request方法的。
# 自定義mymiddleware.py
from django.utils.deprecation import MiddlewareMixin
class MyMdd1(MiddlewareMixin):
    def process_request(self, request):
        print('我是mdd1的request方法')

class MyMdd2(MiddlewareMixin):
    def process_request(self, request):
        print('我是mdd2的request方法')

# views.py
def ab_md(request):
    print('我是檢視函式ab_md')
    return HttpResponse('ab_md')
   
# settions.py
MIDDLEWARE = [
    'app01.mymiddleware.MyMdd1',  # 自定義中介軟體mdd1
    'app01.mymiddleware.MyMdd2'   # 自定義中介軟體mdd2
]

後端列印:
    我是mdd1的request方法
    我是mdd2的request方法
    我是檢視函式ab_md
    
# 總結:
    1.中介軟體的process_request方法是在執行檢視函式之前執行的
    2.當配置多箇中介軟體時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後的一次執行。
    3.不同中介軟體之間傳遞的request都是同一個物件
    4.當該方法返回了HttpResponse物件,那麼請求不再繼續往後執行,而是直接原路返回

process_response

# 自定義mymiddleware.py
class MyMdd1(MiddlewareMixin):
    def process_request(self, request):
        print('我是mdd1的request方法')

    def process_response(self, request,response):
        print('我是mdd1的response方法')
        return response

class MyMdd2(MiddlewareMixin):
    def process_request(self, request):
        print('我是mdd2的request方法')

    def process_response(self, request,response):
        print('我是mdd2的response方法')
        return response
    
# 其餘和上述程式碼一致
後端列印:
    我是mdd1的request方法
    我是mdd2的request方法
    我是檢視函式ab_md
    我是mdd2的response方法
    我是mdd1的response方法
    
# 總結:
    1.當響應返回的時候會從下往上依次執行每一箇中間           件裡面的該方法,如果沒有則直接下一個 該方法預設要返回response
    
    2.該方法返回什麼瀏覽器就會接收到什麼(也就意味著我們可以中途攔截待返回的資料做其他處理)  # 原理和擊鼓傳花一樣,一個傳一個
    
    3.當中介軟體返回了HttpResponse物件,那麼請求不再繼續往後執行,而是直接原路返回
    # process_request方法如果直接返回HttpResonse物件則直接執行process_response原路返回

相關文章