Day14 session原理和中介軟體

A1L__發表於2020-10-23

Day14 session原理和中介軟體

views檢視函式

def index(request):
    return HttpResponse('檢視函式好了!')


def login(request):
    return HttpResponse('我是登入函式')

已在urls註冊

一、什麼是中介軟體

它是一個輕量、低階別的外掛系統,用於在全域性範圍內改變Django的輸入和輸出。每個中介軟體元件都負責做一些特定的功能。

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

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',
      'app01.Mymiddleware.Mymiddleware.Middle1',
    'app01.Mymiddleware.Mymiddleware.Middle2',
]

MIDDLEWARE配置項是一個列表(列表是有序的,記住這一點,後面你就知道為什麼要強調有序二字),列表中是一個個字串,這些字串其實是一個個類,也就是一個個中介軟體。

-請求的時候從上往下執行:process_request
-請求的時候從下往上執行:process_response

1.process_request方法

class Middle1(MiddlewareMixin):
    
    def process_request(self, request):
        print('這是通過我Middle1的request!')
        
        
class Middle2(MiddlewareMixin):
    
    def process_request(self, request):
        print('這是通過我Middle2的request!')

這裡是定義的兩個請求方法,然後我們執行專案,看看結果如何

由此總結一下:

  1. 中介軟體的process_request方法是在執行檢視函式之前執行的。
  2. 當配置多箇中介軟體時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後依次執行的。
  3. 不同中介軟體之間傳遞的request都是同一個物件

image-20201023164606994

我們可以看他執行的方式,是我們註冊方式的從上而下,會一次執行每一箇中介軟體,就像豬肉質檢層層把關

2.process_response方法

class Middle1(MiddlewareMixin):
    
    def process_request(self, request):
        print('這是通過我Middle1的request!')
    
    def process_response(self, request, response):
        print('這是通過我Middle1的response!')
        return response  # 必須要返回response
     
        
class Middle2(MiddlewareMixin):
    
    def process_request(self, request):
        print('這是通過我Middle2的request!')
    
    def process_response(self, request, response):
        print('這是通過我Middle2的response!')
        return response

然後我們來執行一下

image-20201023165106286

執行結果是不是很像 之前的多個裝飾器

注意:

定義process_response方法時,必須給方法傳入兩個形參,request和response。request就是上述例子中一樣的物件,response是檢視函式返回的HttpResponse物件(也就是說這是Django後臺處理完之後給出一個的一個具體的檢視)。該方法的返回值(必須要有返回值)也必須是HttpResponse物件。如果不返回response而返回其他物件,則瀏覽器不會拿到Django後臺給他的檢視,而是我的中介軟體中返回的物件

這裡我們來修改一下返回的物件

class Middle2(MiddlewareMixin):
    
    def process_request(self, request):
        print('這是通過我Middle2的request!')
    
    def process_response(self, request, response):
        print('這是通過我Middle2的response!')
        return HttpResponse('我是Middle2自定義的response')

image-20201023165745799

3.process_view方法

引數配置

該方法有四個引數

request是HttpRequest物件。

view_func是Django即將使用的檢視函式。 (它是實際的函式物件,而不是函式的名稱作為字串。)

view_args是將傳遞給檢視的位置引數的列表.

view_kwargs是將傳遞給檢視的關鍵字引數的字典。 view_args和view_kwargs都不包含第一個檢視引數(request)。

Django會在呼叫檢視函式之前呼叫process_view方法。

class Middle1(MiddlewareMixin):
    
    def process_request(self, request):
        print('這是通過我Middle1的request!')
    
    def process_response(self, request, response):
        print('這是通過我Middle1的response!')
        return response  # 必須要返回response
    
    def process_view(self, request,view_func, view_args, view_kwargs):
        print(request.method)
        print(view_func.__name__)  # 會自動捕獲所呼叫的函式,也就是根據url分發的網址與函式關係
        print(view_func)
        return HttpResponse('54088')


class Middle2(MiddlewareMixin):
    
    def process_request(self, request):
        print('這是通過我Middle2的request!')
    
    def process_response(self, request, response):
        print('這是通過我Middle2的response!')
        return response
    
    def process_view(self, request,view_func, view_args, view_kwargs):
        print(view_func.__name__)
        print(view_func)
        print(view_args)
        return HttpResponse('54099')

試一試,訪問login頁面

image-20201023170932890

總結:

  1. 在urls.py之後在執行真正的檢視函式之前
  2. 按照在列表中註冊的順序依次執行
  3. 返回值1.返回None,放行
  4. 返回值2.返回響應物件,就直接跳出,倒序依次執行所有中介軟體的process_response方法

like this

4.process_exception方法

process_exception(self, request, exception)

一個HttpRequest物件

一個exception是檢視函式異常產生的Exception物件。

這個方法只有在檢視函式中出現異常了才執行,它返回的值可以是一個None也可以是一個HttpResponse物件(程式bug返回404)。如果是HttpResponse物件,Django將呼叫模板和中介軟體中的process_response方法,並返回給瀏覽器,否則將預設處理異常。如果返回一個None,則交給下一個中介軟體的process_exception方法來處理異常。它的執行順序也是按照中介軟體註冊順序的倒序執行

class Middle1(MiddlewareMixin):
    
    def process_request(self, request):
        print('這是通過我Middle1的request!')
    
    def process_response(self, request, response):
        print('這是通過我Middle1的response!')
        return response  # 必須要返回response
    
    def process_view(self, request, view_func, view_args, view_kwargs):
        pass
    
    def process_exception(self, request, exception):
        print('middle1的', exception)
        return HttpResponse('404')


class Middle2(MiddlewareMixin):
    
    def process_request(self, request):
        print('這是通過我Middle2的request!')
    
    def process_response(self, request, response):
        print('這是通過我Middle2的response!')
        return response
    
    def process_view(self, request, view_func, view_args, view_kwargs):
        pass
    
    def process_exception(self, request, exception):
        print('middle2的', exception)
        print('我捕獲到了錯誤,但是我不想處理,留給Middle1')

image-20201023172920143

5.process_template_response方法(用的比較少)

process_template_response(用的比較少)

process_template_response(self, request, response)

它的引數,一個HttpRequest物件,response是TemplateResponse物件(由檢視函式或者中介軟體產生)。

process_template_response是在檢視函式執行完成後立即執行,但是它有一個前提條件,那就是檢視函式返回的物件有一個render()方法(或者表明該物件是一個TemplateResponse物件或等價方法)。

總結

img

如果request也有返回值,也是直接到自己位置的response,之前的response(3,4,5,6)不會走,直接就跳過了

二、CSRF_TOKEN跨站請求偽造

CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站指令碼(XSS),但它與XSS非常不同,XSS利用站點內的信任使用者,而CSRF則通過偽裝來自受信任使用者的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防範的資源也相當稀少)和難以防範,所以被認為比XSS更具危險性

可以這樣來理解:
攻擊者盜用了你的身份,以你的名義傳送惡意請求,對伺服器來說這個請求是完全合法的,但是卻完成了攻擊者所期望的一個操作,比如以你的名義傳送郵件、發訊息,盜取你的賬號,新增系統管理員,甚至於購買商品、虛擬貨幣轉賬等。 如下:其中Web A為存在CSRF漏洞的網站,Web B為攻擊者構建的惡意網站,User C為Web A網站的合法使用者

1. CSRF攻擊原理

如下圖:

img

從上圖可以看出,要完成一次CSRF攻擊,受害者必須依次完成兩個步驟:

1.登入受信任網站A,並在本地生成Cookie。

2.在不登出A的情況下,訪問危險網站B。

看到這裡,你也許會說:“如果我不滿足以上兩個條件中的一個,我就不會受到CSRF的攻擊”。是的,確實如此,但你不能保證以下情況不會發生:

1.你不能保證你登入了一個網站後,不再開啟一個tab頁面並訪問另外的網站。

2.你不能保證你關閉瀏覽器了後,你本地的Cookie立刻過期,你上次的會話已經結束。(事實上,關閉瀏覽器不能結束一個會話,但大多數人都會錯誤的認為關閉瀏覽器就等於退出登入/結束會話了…)

3.上圖中所謂的攻擊網站,可能是一個存在其他漏洞的可信任的經常被人訪問的網站。

2. CSRF攻擊防範

說簡單點我們的django已經幫我們做到的防範,也就是多重校驗,標籤

crsf_token

3.在form表單中應用

<form action="" method="post">
    {% csrf_token %}
    <p>使用者名稱:<input type="text" name="name"></p>
    <p>密碼:<input type="text" name="password"></p>
    <p><input type="submit"></p>
</form>

4.在Ajax中應用:

方式一:放到data中
     $.ajax({
            url: '/csrf_test/',
            method: 'post',
            data: {'name': $('[name="name"]').val(),
                'password': $('[name="password"]').val(),
                'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()
            },
            success: function (data) {
                console.log('成功了')
                console.log(data)

            },
            error: function (data) {
                console.log('xxxxx')
                console.log(data)

            }
        })
        方式二:放到data中
        'csrfmiddlewaretoken':'{{ csrf_token }}'
        方式三:放到頭中
        	headers:{'X-CSRFToken':'{{csrf_token}}'},
        
        
 # jquery.cookie.js
	-在瀏覽器中對cookie進行增,刪,查,改
    -前後端分離(js操作cookie)
    
    
    
# 全域性使用,區域性禁csrf
	-在檢視函式上加裝飾器
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
# 全域性啟用,區域性禁用(中介軟體不能註釋,這個檢視函式,已經沒有csrf校驗了)
# @csrf_exempt
# def csrf_test(request):
#     if request.method=='GET':
#         return render(request,'csrf_test.html')
#     else:
#         name=request.POST.get('name')
#         password=request.POST.get('password')
#         print(name)
#         print(password)
#         return HttpResponse('登入成功')

# 全域性禁用,區域性使用csrf
@csrf_protect
def csrf_test(request):
    if request.method=='GET':
        return render(request,'csrf_test.html')
    else:
        name=request.POST.get('name')
        password=request.POST.get('password')
        print(name)
        print(password)
        return HttpResponse('登入成功')



# 古怪的使用方式,在urls.py中
path('csrf_test/', csrf_exempt(views.csrf_test))

相關文章