Django雜篇(2)

Django雜篇(2)

本文主要介紹cookie與session組件,django中間件以及CSRF的一些介紹.前端

cookie與session

首先咱們要知道,HTTP協議自己是無狀態的,無狀態的概念是什麼?python

無狀態的意思就是當用戶的請求經過HTTP發給後端的時候,HTTP自己是不保留用戶的任何狀態的,即每次用戶發送HTTP都會當作是用戶第一次發送數據,這是很是不合理的,試想一下,若是咱們登錄一個購物網站,登錄成功以後想要作購買商品,但是是作不了的,由於HTTP無狀態,每次登錄都是第一次登錄,咱們老是在不停地登錄,就沒辦法作任何操做.ajax

因此就引出了cookie和session的概念,他們都是用來讓用戶"保持狀態"的,便可以讓用戶處於登錄狀態下,從而進行一系列的操做.數據庫

cookie的實際本體只是一段字符串,他是從服務器發送出來而且存放在瀏覽器(客戶端)上的一組組鍵值對,當瀏覽器下次訪問服務端的時候,就會在request請求裏面自動攜帶這個字符串,服務端就能夠識別這個字符串,根據這個cookie來解析出你的身份,哦,原來咱們以前見過,並且進行過一些互動~django

查看cookie也很是簡單,咱們只須要在任何瀏覽器裏面,按F12->找到Network標籤->找到下面的二級標籤Cookies便可,裏面就是當前網頁的cookie信息.後端

那麼咱們在django裏面怎麼對cookie作操做呢,實例以下:瀏覽器

# 獲取cookie
request.COOKIES.get('key')#由於cookie實際上是一個字典,因此用get取值比較好,取值時候儘可能不要用中括號取值,由於中括號取值若是取不到會報錯,影響整個項目的運行


# 設置cookie
# 要先取到一個對象,能夠是HttpResponse(),也能夠是render()或者redirect()
obj = HttpResponse()
obj.set_cookie(key,value...)


# 刪除cookie
# 一樣須要先取到一個對象,而後對其作操做
obj = HttpResponse()
obj.delete_cookies("key")

session

既然咱們已經有了cookie這個能夠保持用戶狀態的工具,爲何還要引入session的概念呢?大體緣由有如下兩條:安全

  1. cookie自己支持的長度較小,最大隻支持4096字節,不足以支持很是大的項目以及用戶量
  2. cookie自己存在瀏覽器(客戶端),咱們知道存在於瀏覽器的數據是公開的,並不安全,使用者能夠隨時更改或者攔截這些數據,從而拿着這些cookie來作非法的事情,不太安全

因此,爲了解決以上兩個問題,咱們引入了session的概念,一方面session能夠支持更大的數據,另外一方面session是存放於服務端的,安全性比存放於瀏覽器的cookie要高得多.服務器

話雖如此,但其實session並非取代cookie而存在的東西,而是共存的事物,由於cookie解決的是HTTP協議的無狀態的問題,讓服務端知道來的用戶是誰,而後咱們經過cookie識別不一樣的用戶,進而在服務端的session裏面保存該用戶私密的信息,以及那些長度超過cookie限制的文本數據.

另外要注意一點的是,在django裏面的session的產生是針對同一臺機器的不一樣瀏覽器而言的,即咱們使用同一臺機器的同一個瀏覽器在後端的數據庫表裏永遠只會有一條session記錄,新生成的會把舊的覆蓋掉,只有咱們更換瀏覽器或者更換機器纔會生成兩條不一樣的session記錄.

下面介紹咱們怎麼樣在django裏面對session操做

# 獲取session
request.session.get('key',None)
# 同樣用get取值,若是值不存在就返回None
request.session.session_key
# 能夠獲取該會話session的key值

# 設置session值
request.session['key']=value
request.session.setdefault('key',value)
# 能夠直接用key,value的方式進行賦值,setdefault的優點在於若是設置的值已經存在則不會改變原值,若是不存在就會添加值
request.session.set_expiry(value=)
'''能夠配置session的有效時間,裏面的參數value有多種寫法
1. 若是寫的是數字,就是按秒計算有效時間,數字即爲秒數
2. 若是爲0,則session在關閉瀏覽器後就會失效,即只會生效在當前打開的瀏覽器中
3. 若是爲空白,就會使用django默認的時間,即14天的有效時間
4. 若是爲是一個datetime或者timedelta時間,則會在這個時間後失效
'''

# 刪除session值
del request.session['key']
request.session.delete()    #只會刪除服務端的session
request.session.flush()     #會同時刪除服務端的session和客戶端的cookie

使用session還有一個好處:客戶端只有cookie的值,並不能直接看到用戶的信息,然後端的session是依賴於cookie的,因此這裏就造成了一個先後端分離的狀態,cookie保存在客戶端,session保存在服務端,極大提高了數據的安全性.

django中間件

首先,咱們要了解什麼是中間件?

就名字來看,中間件就是中間的一個組件,咱們能夠把咱們整個後端當作一個學校,那麼中間件就是學校的門衛室,無論用戶的請求進入後端或者是從後端出來,都要通過中間件的檢查,檢查不經過就沒法繼續交互.

上面是按照生活中的見解來講的,就官方的說法來講,中間件就是一個鉤子,一個用來處理Django的請求和響應的鉤子,能夠用來控制全局範圍內Django的輸入和輸出,經常使用的中間件有七個,每一箇中間件都會負責一些特定的功能,且這些功能大多生效在視圖函數的執行以前或者執行以後,中間件的本質仍是一個類,以類中定義方法的形式來限制Django的輸入和輸出的格式.

其實咱們以前已經接觸過中間件,只不過當時咱們都是把其中的一條註釋掉,由於不註釋的話會影響咱們程序的正常運行,自今天起咱們就不用作註釋掉這麼low的操做了,咱們能夠光明正大的去使用而且能夠嘗試本身寫中間件了.

首先咱們要知道中間件在哪裏,在settings.py文件裏,以下:

# settings.py
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',
]
# 首先,該配置項是一個列表,請求在通過中間件的時候是從上到下進入這些方法進行判斷的
# 以上就是系統默認的七個中間件,固然咱們能夠手動寫一個屬於本身的中間件,固然,在本身寫中間件以前,咱們要先了解一下這些中間件都包含有什麼方法,以及是怎麼運做的

自定義中間件

咱們先來看如何自定義中間件:

  1. 首先咱們須要新建一個文件夾(這裏咱們命名爲mymiddleware),任意名字均可以,而後裏面建一個任意名字的py文件(這裏咱們命名爲myaabb.py),裏面寫一個類,有固定的繼承的父類

    #/app01/mymiddleware/myaabb/
    from django.utils.deprecation import MiddlewareMixin
    class MyMiddle(MiddlewareMixin):
            ...
  2. 創建好類以後,咱們還須要去settings.py文件裏面註冊,註冊很是簡單,就是把咱們建立這個文件夾和文件的路徑寫入MIDDLEWARE的列表裏就能夠了.

    # settings.py
    MIDDLEWARE = [
         'app01.mymiddleware.myaabb.MyMiddlel',
    ]

下面咱們就能夠在咱們自定義的文件中定義類和寫咱們須要的方法了,其實中間件裏面經常使用的自定義方法只有五個,每一箇中間件裏所定義的方法也都在這五個方法以內,以下:

'''
1.process_request:該方法是請求來的時候自動觸發,要注意點,在該方法內若是有return HTTPResponse(),那麼以後的中間件都不會再執行,會執行同一級別的process_response,而後從該中間件直接返回,實例以下
'''
def process_request(self,request):
    print('我是自定義中間件裏面的process_request方法')
    return HttpResponse("我是自定義中間件裏面的HttpResponse對象返回值")  # 直接原地返回
    
'''
2.process_response:該方法是響應走的時候調用的,即請求在通過了中間件,urls,views以後,返回值再次走到中間件的時候會調用process_response,且調用順序是從下到上,即MIDDLEWARE裏面從下到上的調用每一箇中間件的process_response
'''
def process_response(self,request,response):  # response就是要返回給用戶的數據
    print("我是第一個自定義中間件裏面的process_response方法")
    return response     # 這裏要注意,凡是形參裏面帶有response的,最後必定要return response,不然返回值數據會丟失

'''
3. process_view:會在路由(urls.py)匹配成功以後執行視圖函數(views.py)以前觸發
4. process_exception:當視圖函數(views.py)出現bug的時候自動觸發
5. process_template_response:當視圖函數執行完畢以後而且返回的對象中含有render方法的狀況下才會觸發(最不經常使用)
'''

跨站請求僞造(csrf)

跨站請求僞造,全稱(Cross-site request forgery),可能咱們會對這個名字比較陌生,可是換個叫法咱們就熟悉了,釣魚網站.簡單來講就是欺騙用戶的瀏覽器,讓其以用戶的名義運行操做,達到製做釣魚網站的人的目的.

CSRF的解決方案

CSRF最經常使用的解決方案便是添加一個校驗用token,改數據不保存在cookie中,且攻擊者很難僞造,token其本質就是一串隨機數,是由服務端生成併發給客戶端的,在客戶端提交數據的時候會隨着數據一塊兒提交,供服務端來校驗,校驗經過纔會接收客戶端的請求並作處理,若token錯誤或爲空,服務端就會拒絕這個請求

添加校驗token

FORM表單添加

form表單添加token很是簡單,在form表單的內部直接加上{% csrf_token %}便可,在任何位置均可以.

AJAX添加

AJAX添加token的方法經常使用的有三種

# 1. 經過標籤查找並添加
data:{'username':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()}
    
# 2. 經過django的模板語法來添加,這種方法用處有限,由於若是先後端分離的話,後端可能不會用django來搭建,因此模板語法也就不能使用了.
data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
    
# 3. 拷貝一個js文件,而後導入到前端的html文件裏便可,這裏咱們新建static文件夾,並在裏面新建一個setup.js文件而後粘貼如下代碼
# /static/setup.js
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');



function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});


# 完成以後咱們還須要配置兩個地方,一個就是settings.py,一個就是咱們的html文件裏,AJAX的上方
# settings.py
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static')
]

# **.html,直接導入該js文件便可
<script src="/static/setup.js"></script>

裝飾器方式

裝飾器方式主要是用於CBV上,且使用時候要注意

  1. csrf_exempt只能用於CBV裏面的dispatch方法上面,不能用於別的方法
  2. 除了csrf_exempt以外,其餘全部的裝飾器均可以加在不一樣的方法上,好比get或者post

好比:

from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
# csrf_exempt  只能用於裝飾dispatch
# 第一種
# @method_decorator(csrf_exempt,name='dispatch')
class MyCsrf(View):
    # 第二種
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def get(self,request):
        return HttpResponse('hahaha')

# 除了csrf_exempt以外 全部的其餘裝飾器 在CBV上面都有三種方式,即在類外部,或者類內部的方法上方
@method_decorator(csrf_protect,name='post')
class MyCsrf(View):
    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def get(self,request):
        return HttpResponse('hahaha')
    @method_decorator(csrf_protect)
    def post(self,request):
        return HttpResponse('post')
相關文章
相關標籤/搜索