海洋探索生存遊戲《Breakwaters》釋出最新實機演示
阿新 • • 發佈:2021-06-17
目錄
django之中介軟體
一 中介軟體簡介
# 中介軟體顧名思義,是介於request與response處理之間的一道處理過程,相對比較輕量級,並且在全域性上改變django的輸入與輸出。因為改變的是全域性,所以需要謹慎實用,用不好會影響到效能 # django內建中介軟體 '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', # Django預設的中介軟體: -在django專案的settings模組中,有一個 MIDDLEWARE_CLASSES 變數,其中每一個元素就是一箇中間件
# Django中介軟體的定義:
Middleware is a framework of hooks into Django’s request/response processing.
It’s a light, low-level “plugin” system for globally altering Django’s input or output.
二 自定義中介軟體
1 自定義步驟:
1)-寫一個類,繼承MiddlewareMixin 2)-裡面寫方法process_request(請求來了,一定會觸發它的執行) 3)-在setting中配置(注意,放在前和放在後) MIDDLEWARE = [ ... 'app01.mymiddle.MyMiddleware1', ... ]
# MiddlewareMixin類 # from django.utils.deprecation import MiddlewareMixin class MiddlewareMixin: def __init__(self, get_response=None): self.get_response = get_response super().__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response
2 中介軟體主要方法:
# 1) 中介軟體中主要有幾個方法:
process_request(self,request)
process_response(self, request, response)
----------------------------------------------
process_view(self, request, callback, callback_args, callback_kwargs)
process_exception(self, request, exception)
----------------------------------------------
process_template_response(self,request,response)
3 process_request和process_response
0) 是使用最多的兩種方法!!
1) process_request(request物件)
2) process_response(request物件,response物件)
3) 多箇中間件,執行順序是什麼?
-請求來的時候,從上往下執行:process_request
-請求走的時候,從下往上執行:process_response
4) process_request可以幹什麼?【應用場景】
-寫一箇中間件,不管前端用什麼編碼,在requset.data中都有post的資料
-頻率限制(限制某個ip地址,一分鐘只能訪問5次)
-登入認證(只要沒登入,重定向到login路徑)、
-記錄使用者訪問日誌(ip,時間,訪問路徑)
5) process_response可以幹什麼?內部有response物件【應用場景】
-統一給所有(某幾個路徑)加cookie
-統一給所有(某幾個路徑)加響應頭
6) process_request和process_response執行流程:
-當用戶發起請求的時候會依次經過所有的的中介軟體,這個時候的請求是process_request, 最後到達views的函式中,views函式處理後,再依次穿過中介軟體,這個時候是process_response,最後返回給請求者。
上述截圖中的中介軟體都是django中的,我們也可以自己定義一箇中間件,我們可以自己寫一個類,但是必須繼承MiddlewareMixin。
7) 自定義中介軟體的詳細執行流程
-7.1) 第一步:匯入
-from django.utils.deprecation import MiddlewareMixin
-7.2) 第二步:自定義中介軟體程式碼
from django.utils.deprecation import MiddlewareMixin
# process_request
# process_response
from django.shortcuts import render, HttpResponse
class MyMiddleware1(MiddlewareMixin):
# 所有的請求來了,都會走到它
def process_request(self, request):
print('請求來了1')
# print(request.session)
# 可不可以返回?必須返回HttpResponse的物件
# return HttpResponse('我不讓你訪問') # 執行到這裡就直接返回,後續的程式碼不再執行
# 所有的請求走了,都會執行它
def process_response(self, request, response):
print('請求走了1')
# response['name'] = 'lxx'
# print(response) # <HttpResponse status_code=200, "text/html; charset=utf-8">
return response # 此處必須return這個response,不寫的話預設返回None,後續中介軟體會用到response,找不到就會報錯
class MyMiddleware2(MiddlewareMixin):
# 所有的請求來了,都會走到它
def process_request(self, request):
print('請求來了2')
# return HttpResponse('dsb, 檢視函式不執行了吧')
# 所有的請求走了,都會執行它
def process_response(self, request, response):
print('請求走了2')
return response
-7.3) 在view中定義一個檢視函式(index)
def index(request):
print('我是檢視函式')
return HttpResponse('ok')
-7.4) 第四步:在settings.py的MIDDLEWARE裡註冊自己定義的中介軟體
# 執行結果
"""請求來了1
請求來了2
我是檢視函式
請求走了2
請求走了1"""
8) 注意:
-如果當請求到達請求2的時候直接不符合條件返回,即return HttpResponse("Md2中斷"),程式將把請求直接發給中介軟體2返回,然後依次返回到請求者,結果如下:
-返回Md2中斷的頁面,後臺列印如下:
"""
Md1請求
Md2請求
Md2返回
Md1返回"""
流程圖如下:
9) 總結:
-中介軟體的process_request方法是在執行檢視函式之前執行的。
-當配置多箇中間件時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後依次執行的。
-不同中介軟體之間傳遞的request都是同一個物件
-多箇中間件中的process_response方法是按照MIDDLEWARE中的註冊順序倒序執行的,也就是說第一個中介軟體的process_request方法首先執行,而它的process_response方法最後執行,最後一箇中間件的process_request方法最後一個執行,它的process_response方法是最先執行。
4 process_view
-Django會在路由匹配成功,呼叫檢視函式之前呼叫process_view方法。
def process_view(self, request, callback, callback_args, callback_kwargs):
# 該方法有四個引數
-request # 是HttpRequest物件。
-callback # 是Django即將使用的檢視函式。 (它是實際的函式物件,而不是函式的名稱作為字串。)
-callback_args # 是將傳遞給檢視的位置引數的列表.
-callback_kwargs # 是將傳遞給檢視的關鍵字引數的字典。 view_args和view_kwargs都不包含第一個檢視引數(request)。
-它應該返回None或一個HttpResponse物件。 如果返回None,Django將繼續處理這個請求,執行任何其他中介軟體的process_view方法,然後在執行相應的檢視。 如果它返回一個HttpResponse物件,Django不會呼叫適當的檢視函式。 它將執行中介軟體的process_response方法並將應用到該HttpResponse並返回結果。
# process_view正常的執行:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
class MyMiddleware1(MiddlewareMixin):
# 所有的請求來了,都會走到它
def process_request(self, request):
print('請求來了1')
# print(request.session)
# 可不可以返回?必須返回HttpResponse的物件
# return HttpResponse('我不讓你訪問') # 執行到這裡就直接返回,後續的程式碼不再執行
# 所有的請求走了,都會執行它
def process_response(self, request, response):
print('請求走了1')
# response['name'] = 'lxx'
# print(response) # <HttpResponse status_code=200, "text/html; charset=utf-8">
return response # 此處必須return這個response,不寫的話預設返回None,後續中介軟體會用到response,找不到就會報錯
def process_view(self, request, callback, callback_args, callback_kwargs):
print('中介軟體1的process_view')
class MyMiddleware2(MiddlewareMixin):
# 所有的請求來了,都會走到它
def process_request(self, request):
print('請求來了2')
# return HttpResponse('dsb, 檢視函式不執行了吧')
# 所有的請求走了,都會執行它
def process_response(self, request, response):
print('請求走了2')
return response
# 執行結果:
"""請求來了1
請求來了2
中介軟體1的process_view
我是檢視函式
請求走了2
請求走了1"""
# 執行流程圖:
# process_view可以用來呼叫檢視函式:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
class MyMiddleware1(MiddlewareMixin):
# 所有的請求來了,都會走到它
def process_request(self, request):
print('請求來了1')
# print(request.session)
# 可不可以返回?必須返回HttpResponse的物件
# return HttpResponse('我不讓你訪問') # 執行到這裡就直接返回,後續的程式碼不再執行
# 所有的請求走了,都會執行它
def process_response(self, request, response):
print('請求走了1')
# response['name'] = 'lxx'
# print(response) # <HttpResponse status_code=200, "text/html; charset=utf-8">
return response # 此處必須return這個response,不寫的話預設返回None,後續中介軟體會用到response,找不到就會報錯
def process_view(self, request, callback, callback_args, callback_kwargs):
res = callback(request)
print('中介軟體1的process_view')
return res
# 執行結果:
"""請求來了1
請求來了2
我是檢視函式
中介軟體1的process_view
請求走了2
請求走了1"""
# 注意:
-process_view如果有返回值,會越過其他的process_view以及檢視函式,但是所有的process_response都還會執行。
5 process_exception
-檢視函數出錯,緊後會執行它(全域性異常捕獲)("記錄日誌,哪個ip地址,訪問哪個路徑,出的錯")# 全域性異常捕獲,返回4開頭的
def process_exception(self, request, exception):
# 該方法兩個引數:
-一個HttpRequest物件
-一個exception是檢視函式異常產生的Exception物件。
-這個方法只有在檢視函式中出現異常了才執行,它返回的值可以是一個None也可以是一個HttpResponse物件。如果是HttpResponse物件,Django將呼叫模板和中介軟體中的process_response方法,並返回給瀏覽器,否則將預設處理異常。如果返回一個None,則交給下一個中介軟體的process_exception方法來處理異常。它的執行順序也是按照中介軟體註冊順序的倒序執行。
# process_exception方法來處理異常:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
class MyMiddleware1(MiddlewareMixin):
# 所有的請求來了,都會走到它
def process_request(self, request):
print('請求來了1')
# print(request.session)
# 可不可以返回?必須返回HttpResponse的物件
# return HttpResponse('我不讓你訪問') # 執行到這裡就直接返回,後續的程式碼不再執行
# 所有的請求走了,都會執行它
def process_response(self, request, response):
print('請求走了1')
# response['name'] = 'lxx'
# print(response) # <HttpResponse status_code=200, "text/html; charset=utf-8">
return response # 此處必須return這個response,不寫的話預設返回None,後續中介軟體會用到response,找不到就會報錯
def process_view(self, request, callback, callback_args, callback_kwargs):
# res = callback(request)
print('中介軟體1的process_view')
# return res
class MyMiddleware2(MiddlewareMixin):
# 所有的請求來了,都會走到它
def process_request(self, request):
print('請求來了2')
# return HttpResponse('dsb, 檢視函式不執行了吧')
# 所有的請求走了,都會執行它
def process_response(self, request, response):
print('請求走了2')
return response
# 全域性異常捕獲,返回4開頭的
def process_exception(self, request, exception):
print(exception)
print('exception')
return HttpResponse('error')
# return render(request, 'error.html')
[views.py]:
from django.shortcuts import render, HttpResponse
def index(request):
print('我是檢視函式')
a
return HttpResponse('ok')
# return render(request, 'index.html')
# 執行結果:
"""請求來了1
請求來了2
中介軟體1的process_view
我是檢視函式
name 'a' is not defined
exception
請求走了2
請求走了1"""
# 流程圖如下:
# 總結:
-以檢視函式為中間點,檢視函式之前的 process_request和 process_view都是"自上至下"執行,
-檢視函式之後的 process_exception和 process_response都是"自下至上"執行。
6 process_template_response
-使用較少:
-該方法對檢視函式返回值有要求,必須是一個含有render方法類的物件,才會執行此方法
三 CSRF_TOKEN跨站請求偽造
1 什麼是跨站請求偽造
# 攻擊者盜用了你的身份,以你的名義傳送惡意請求,對伺服器來說這個請求是完全合法的。
2 django中介軟體解決csrf攻擊
# 中介軟體的使用:django.middleware.csrf.CsrfViewMiddleware
django中介軟體會瀏覽器在傳送post請求的時候,給請求加上一個k:v形式的csrf_token字串返回瀏覽器,並且有一個過期時間,下次再請求的時候需要驗證這個字串,沒有字串的請求就會拒絕訪問。
# 1) form表單提交
-在form表單中 {% csrf_token %}
# 檢視函式
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('登入成功!')
# HTML
<form action="" method="post">
{% csrf_token %}
<p>使用者名稱:<input type="text" name="name"></p>
<p>密碼:<input type="password" name="password"></p>
<p><input type="submit" value="提交"></p>
</form>
# 2) ajax提交
# html
{% csrf_token %}
<p>使用者名稱:<input type="text" name="name"></p>
<p>密碼:<input type="password" name="password"></p>
<p><input type="submit" value="提交" id="submit"></p>
// 方式一:放到data中
$('#submit').click(function () {
$.ajax({
url: '/app01/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('lxxxxxxxxx')
console.log(data)
}
})
})
// 方式二:放到data中
'csrfmiddlewaretoken':'{{ csrf_token }}'
// 方式三:放到請求頭中
$('#submit').click(function () {
$.ajax({
url: '/app01/csrf_test/',
method: 'post',
headers:{'X-CSRFToken':'{{csrf_token}}'},
data: {'name': $('[name = "name"]').val(),
'password': $('[name = "password"]').val(),
// 'csrfmiddlewaretoken': $('[name = "csrfmiddlewaretoken"]').val(), //必須加,不然後403forbidden
// 'csrfmiddlewaretoken': '{{ csrf_token }}', //必須引號,否則就不是字串了
},
success: function (data) {
console.log('成功了')
console.log(data)
},
error: function (data) {
console.log('lxxxxxxxxx')
console.log(data)
}
})
})
# 3) 使用jquery.cookie.js
-從cookie中取,則網頁中的{% csrf_token %}就不需要了
-在瀏覽器中對cookie進行增,刪,查,改
-前後端分離(js操作cookie)
3 csrf的區域性使用、區域性禁用
# 如何區域性使用/禁用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_token本可以正常使用,加上這個裝飾器,就必須帶上csrf_token才能使用了)
@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))