中間件是一個用來處理Django的請求和響應的框架級別的鉤子,用於在全局範圍內改變Django的輸入和輸出,只要是全局相關的功能都應該考慮使用Django中間件來完成html
中間件在settings配置文件中web
from django.middleware.security import SecurityMiddleware # 查看某個中間件代碼方式,直接複製上去用from...import... 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', ]
中間件幹了什麼事?ajax
請求來時由Django中間件默認的七個關口進行校驗,當任意一個校驗不經過都會返回,當七個默認關口都校驗成功後,判斷是否是第一次請求,若是不是,會直接去緩存數據庫中查找數據,拿到數據後再經過中間件默認七個關口,經過web服務網關接口後返回給客戶端瀏覽器數據,當第一次請求來時會依次經過url,views最後到數據庫拿到數據後由視圖層直接到中間件經過七個關口校驗,當校驗成功後,將數據進入緩存數據庫一份,再經過web服務網關接口發送到客戶端瀏覽器一份數據數據庫
咱們也能夠自定義中間件,須要建立一個文件夾下寫自定義中間件代碼,而且須要將自定義的中間件配置到配置文件中,自定義中間件要繼承中間件繼承的 MiddlewraeMixindjango
Django容許自定義中間件而且暴露給用戶五個自定義的方法瀏覽器
一、中間件是在執行視圖函數以前執行的緩存
二、請求來的時候會按照配置文件中註冊的中間件從上往下的順序依次執行每個中間件裏面的process_request方法,若是沒有就直接跳過執行下一個服務器
三、若是中間有一箇中間件有return HttpResponse ,就不會再執行後面的了,就直接同級別執行process_response後返回數據cookie
# 自定義的中間件 from django.utils.deprecation import MiddlewareMixin class Mymd1(MiddlewareMixin): def process_request(self, request): print('我是第1個process_request') class Mymd2(MiddlewareMixin): def process_request(self, request): print('我是第2個process_request')
# settings中配置 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', 'mymiddlewrae.mymiddle.Mymd1', 'mymiddlewrae.mymiddle.Mymd2', ]
# views中 def index(request): print('index') return HttpResponse('index')
最後運行打印結果session
我是第1個process_request
我是第2個process_request
index
響應走的時候會按照配置文件中註冊的中間件從下往上依次執行每個中間件裏面的process_response方法,該方法必需要有兩個形參,且必需要將形參response返回,若是中間件內部定義了HttpResponse對象,返回的時候就會將返回給用戶瀏覽器的內容替換成本身的
# 自定義的中間件 from django.utils.deprecation import MiddlewareMixin class Mymd1(MiddlewareMixin): def process_request(self, request): print('我是第1個process_request') def process_response(self, request, response): print('我是第1個process_response') return response class Mymd2(MiddlewareMixin): def process_request(self, request): print('我是第2個process_request') def process_response(self, request, response): print('我是第2個process_response') return response
最後返回的結果:
我是第1個process_request
我是第2個process_request
index
我是第2個process_response
我是第1個process_response
路由匹配成功以後,進入視圖函數以前觸發
也必需要有兩個參數,response必需要方法,有response的都要返回
視圖函數返回的對象中必需要有render屬性對應的方法,必需要自定義的render方法
# 視圖函數中 def index(request): print('index') def render(): return HttpResponse('我是index中的render方法') obj = HttpResponse('index') obj.render = render return obj
# 自定義中間件 def process_template_response(self,request, response): print('我是第2個process_temlate_response') return response
當視圖函數報錯時自動觸發
# 中間件中 def process_exception(self,request,exception): print('exception:',exception)
釣魚網站:本質就是搭建一個跟正常網站如出一轍的頁面,用戶在該頁面上完成轉帳功能,在給用戶書寫的form表單中,對方帳戶的input中沒有name屬性,本身偷偷地提早寫好一個默認隱藏的具備name屬性的input框
<form action="http://127.0.0.1:8000/transfer/" method="post"> <p>username:<input type="text" name="username"></p> <p>target_user:<input type="text"></p> <input type="text" name="target_user" style="display: none" value="jason"> <p>money:<input type="text" name="money"></p> <input type="submit"> </form>
爲了防止這種狀況發生,咱們能夠在咱們的網站設置csrf_token校驗,來防止跨站僞造請求
原理:由token產生隨機字符串,每次請求都會新生成不一樣的,服務器會將須要用戶填寫數據的(post請求)給她一個隨機字符串,下次發送請求的時候會校驗是否有那個字符串
在form表單內任意位置書寫代碼:
{% csrf_token %}
在data中校驗csrf
一、第一種方式:手動獲取
$.ajax({
url: '',
type: 'post',
{#第一種方法:手動獲取#}
data: {'username':'shen', 'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
success:function (data) {
...
}
})
二、第二種方式:利用模板語法
$.ajax({
url: '',
type: 'post',
{#第二種方法:利用模板語法#}
data: {'username':'shen', 'csrfmiddlewaretoken':{{ csrf_token }},
success:function (data) {
...
}
})
三、第三種方式:通用方式引用外部js文件使全部的post請求都要校驗
外部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); } } });
引用外部js文件後Ajax就能夠正常寫提交請求,就能夠了
<button id="d1">發送Ajax請求</button> {% load static %} <script src="{% static 'mycsrf.js' %}"></script> <script> $('#d1').click(function () { $.ajax({ url: '', type: 'post', {#第三種方法:引用外部js文件,Ajax不要任何操做#} data: {'username':'shen'}, success:function (data) { alert(data) } }) }) </script>
一、當咱們網站引用外部js文件使得整個網站都須要校驗csrf時,想讓幾個視圖函數不校驗時,使用csrf_exempt 裝飾器使得某個視圖函數不校驗csrf
二、當咱們網站總體都不校驗csrf的時候,想讓某幾個視圖函數校驗csrf,能夠使用裝飾器 csrf_protect
首先咱們須要導入該裝飾器
from django.views.decorators.csrf import csrf_exempt, csrf_protect
直接在視圖函數上裝飾@csrf_protect和@csrf_exempt
# @csrf_exempt # 不校驗csrf @csrf_protect # 校驗csrf def home(request): if request.method == 'POST': username = request.POST.get('username') print(username) return render(request, 'mycsrf.html')
首先須要導入csrf_exempt,csrf_protect和method_decorator
from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views import View from django.utils.decorators import method_decorator
一、csrf_protect 校驗csrf
第一種方式:直接在類中的方法使用 @method_decorator(csrf_protect)
from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views import View from django.utils.decorators import method_decorator class Myhome(View): # 第一種方式,直接在類中方法使用 @method_decorator(csrf_protect) def get(self,request): return HttpResponse('get')
第二種方式:給類加裝飾器,指名道姓的給類中的某個方法
from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views import View from django.utils.decorators import method_decorator # 第二種方法,指名道姓給類中post方法裝 @method_decorator(csrf_protect, name='post') class Myhome(View): def get(self,request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
第三種方式:給類中的dispatch方法裝,使全部的方法都得到csrf校驗
from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views import View from django.utils.decorators import method_decorator class Myhome(View): # 第三種方式,給類中的全部方法都裝 @method_decorator(csrf_protect) def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) def get(self,request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
二、csrf_exempt 不校驗csrf
只能給類中的dispatch方法裝,使得全部的方法都得到,或者給類裝指明是給dispatch的也能夠
from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views import View from django.utils.decorators import method_decorator # 給類中全部的方法都裝,使得都不校驗csrf,與直接給dispatch裝同樣的 @method_decorator(csrf_exempt, name='dispatch') class Myhome(View): # 給類中的全部方法都裝 @method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) def get(self,request): return HttpResponse('get') def post(self, request): return HttpResponse('post')