70-django-中間件、csrf跨站請求僞造、csrf校驗、csrf相關裝飾器、模塊補充、基於django中間件一個重要的編程思想

今日內容概要

  • django中間件
    • 首先django自帶七個中間件,每一箇中間件都有各自對應的功能
    • 而且django還支持程序員自定義中間件
    • 你在用django開發項目的項目的時候,只要是涉及到全局相關的功能均可以使用中間件方便的完成
  • 全局用戶身份校驗
  • 全局用戶權限校驗(補充)
  • 全局訪問頻率校驗
  • 基於django中間件一個重要的變成思想(補充)
  • csrf跨站請求僞造

今日內容詳細

django中間件

 1 """
 2 django中間件是django的門戶
 3 1.請求來的時候須要先通過中間件才能到達真正的django後端
 4 2.響應走的時候最後也須要通過中間件才能發送出去
 5 
 6 django自帶七個中間件
 7 """
 8 django請求生命週期流程圖
 9 
10 研究django中間件代碼規律
11 MIDDLEWARE = [
12     'django.middleware.security.SecurityMiddleware',
13     'django.contrib.sessions.middleware.SessionMiddleware',
14     'django.middleware.common.CommonMiddleware',
15     'django.middleware.csrf.CsrfViewMiddleware',
16     'django.contrib.auth.middleware.AuthenticationMiddleware',
17     'django.contrib.messages.middleware.MessageMiddleware',
18     'django.middleware.clickjacking.XFrameOptionsMiddleware',
19 ]
20 
21 class SessionMiddleware(MiddlewareMixin):
22     def process_request(self, request):
23         session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
24         request.session = self.SessionStore(session_key)
25     def process_response(self, request, response):
26         return response
27       
28 class CsrfViewMiddleware(MiddlewareMixin):
29       def process_request(self, request):
30         csrf_token = self._get_token(request)
31         if csrf_token is not None:
32             # Use same token next time.
33             request.META['CSRF_COOKIE'] = csrf_token
34     def process_view(self, request, callback, callback_args, callback_kwargs):
35         return self._accept(request)
36 
37     def process_response(self, request, response):
38         return response
39       
40 class AuthenticationMiddleware(MiddlewareMixin):
41     def process_request(self, request):
42         request.user = SimpleLazyObject(lambda: get_user(request))
43 """
44 django支持程序員自定義中間件而且暴露給程序員五個能夠自定義的方法
45     1.必須掌握
46         process_request
47         
48         process_response
49     2.瞭解便可
50         process_view
51             
52         process_template_response
53         
54         process_exception
55 """

如何自定義中間件

  1 """
  2 1.在項目名或者應用名下建立一個任意名稱的文件夾
  3 2.在該文件夾內建立一個任意名稱的py文件
  4 3.在該py文件內須要書寫類(這個類必須繼承MiddlewareMixin)
  5     而後在這個類裏面就能夠自定義五個方法了
  6     (這五個方法並非所有都須要書寫,用幾個寫幾個)
  7 4.須要將類的路徑以字符串的形式註冊到配置文件中才能生效
  8 MIDDLEWARE = [
  9     'django.middleware.security.SecurityMiddleware',
 10     'django.contrib.sessions.middleware.SessionMiddleware',
 11     'django.middleware.common.CommonMiddleware',
 12     'django.middleware.csrf.CsrfViewMiddleware',
 13     'django.contrib.auth.middleware.AuthenticationMiddleware',
 14     'django.contrib.messages.middleware.MessageMiddleware',
 15     'django.middleware.clickjacking.XFrameOptionsMiddleware',
 16     '你本身寫的中間件的路徑1',
 17     '你本身寫的中間件的路徑2',
 18     '你本身寫的中間件的路徑3',
 19 ]
 20 
 21 """
 22 
 23 '''
 24 from django.utils.deprecation import MiddlewareMixin
 25 from django.shortcuts import render, HttpResponse, redirect
 26 
 27 
 28 class MyMiddleware1(MiddlewareMixin):
 29     def process_request(self, request):
 30         print('第一個自定的process_request方法')
 31         # return HttpResponse('第一個自定的process_request方法')
 32 
 33     def process_response(self, request, response):
 34         print('第一個自定的process_response方法')
 35         return response
 36 
 37     def process_view(self, request, view_name, *args, **kwargs):
 38         print(view_name, args, kwargs)
 39         print('第一個自定的process_view方法')
 40 
 41     def process_template_response(self, request, response):
 42         print('第一個自定的process_template_response方法')
 43         return response
 44 
 45     def process_exception(self, request, exception):
 46         print('第一個自定的process_exception方法')
 47         print(exception)
 48 
 49 
 50 class MyMiddleware2(MiddlewareMixin):
 51     def process_request(self, request):
 52         print('第二個自定的process_request方法')
 53 
 54     def process_response(self, request, response):
 55         print('第二個自定的process_response方法')
 56         return response
 57 
 58     def process_view(self, request, view_name, *args, **kwargs):
 59         print(view_name, args, kwargs)
 60         print('第二個自定的process_view方法')
 61 
 62     def process_template_response(self, request, response):
 63         print('第二個自定的process_template_response方法')
 64         return response
 65 
 66     def process_exception(self, request, exception):
 67         print('第二個自定的process_exception方法')
 68         print(exception)
 69 '''
 70 
 71 """
 72 1.必須掌握
 73         process_request 
 74             1.請求來的時候須要通過每個中間件裏面的process_request方法
 75             結果的順序是按照配置文件中註冊的中間件從上往下的順序依次執行
 76             2.若是中間件裏面沒有定義該方法,那麼直接跳過執行下一個中間件
 77             3.若是該方法返回了HttpResponse對象,那麼請求將再也不繼續日後執行
 78             而是直接原路返回(校驗失敗不容許訪問...)
 79             process_request方法就是用來作全局相關的全部限制功能
 80             
 81         process_response   (它的參數response就是django返回給瀏覽器的內容)
 82             1.響應走的時候須要通過每個中間件裏面的process_response方法
 83             該方法有兩個額外的參數request,response
 84             2.該方法必須返回一個HttpResponse對象
 85                 1.默認返回的就是形參response
 86                 2.你也能夠本身返回本身的
 87             3.順序是按照配置文件中註冊了的中間件從下往上依次通過
 88                 若是你沒有定義的話 直接跳過執行下一個
 89         
 90         研究若是在第一個process_request方法就已經返回了HttpResponse對象,那麼響應走的時候是通過全部的中間件裏面的process_response仍是有其餘狀況
 91         是其餘狀況
 92             就是會直接走同級別的process_reponse返回
 93         
 94         flask框架也有一箇中間件可是它的規律
 95             只要返回數據了就必須通過全部中間件裏面的相似於process_reponse方法
 96             
 97             
 98 2.瞭解便可
 99         process_view
100             路由匹配成功以後執行視圖函數以前,會自動執行中間件裏面的該放法
101             順序是按照配置文件中註冊的中間件從上往下的順序依次執行
102             
103         process_template_response
104             返回的HttpResponse對象有render屬性的時候纔會觸發
105                         只要形參中有response你就必須返回
106             順序是按照配置文件中註冊了的中間件從下往上依次通過
107 '''
108                         def index(request):
109                         print('在下index是也')
110                         obj = HttpResponse('在下index是也')
111                         def render():
112                          print('內部render方法')
113                         return HttpResponse('98K牛逼')
114                         obj.render = render
115                         return obj
116 '''            
117 
118         process_exception
119             當視圖函數中出現異常的狀況下觸發
120                         參數exception就是報錯信息
121             順序是按照配置文件中註冊了的中間件從下往上依次通過
122 """
123                 

csrf跨站請求僞造

 1 """
 2 釣魚網站
 3     我搭建一個跟正規網站如出一轍的界面(中國銀行)
 4     用戶不當心進入到了咱們的網站,用戶給某我的打錢
 5     打錢的操做確確實實是提交給了中國銀行的系統,用戶的錢也確確實實減小了
 6     可是惟一不一樣的時候打錢的帳戶不適用戶想要打的帳戶變成了一個莫名其妙的帳戶
 7 
 8 大學英語四六級
 9     考以前須要學生本身網站登錄繳費
10 
11 內部本質
12     咱們在釣魚網站的頁面 針對對方帳戶 只給用戶提供一個沒有name屬性的普通input框
13     而後咱們在內部隱藏一個已經寫好name和value的input框
14 
15 如何規避上述問題
16     csrf跨站請求僞造校驗
17         網站在給用戶返回一個具備提交數據功能頁面的時候會給這個頁面加一個
18 惟一標識
19         當這個頁面朝後端發送post請求的時候 個人後端會先校驗惟一標識,若是
20 惟一標識不對直接拒絕(403 forbbiden)若是成功則正常執行    
21 """

如何符合校驗

 1 # form表單如何符合校驗
 2 <form action="" method="post">
 3     {% csrf_token %}
 4     <p>username:<input type="text" name="username"></p>
 5     <p>target_user:<input type="text" name="target_user"></p>
 6     <p>money:<input type="text" name="money"></p>
 7     <input type="submit">
 8 </form>
 9 
10 # ajax如何符合校驗
11 // 第一種 利用標籤查找獲取頁面上的隨機字符串
12 {#data:{"username":'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#}
13 // 第二種 利用模版語法提供的快捷書寫
14 {#data:{"username":'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
15 // 第三種 通用方式直接拷貝js代碼並應用到本身的html頁面上便可
16 {% load static %}
17 <script src="{% static 'js/mysetup.js'%}"></script>
 1 function getCookie(name) {
 2     var cookieValue = null;
 3     if (document.cookie && document.cookie !== '') {
 4         var cookies = document.cookie.split(';');
 5         for (var i = 0; i < cookies.length; i++) {
 6             var cookie = jQuery.trim(cookies[i]);
 7             // Does this cookie string begin with the name we want?
 8             if (cookie.substring(0, name.length + 1) === (name + '=')) {
 9                 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
10                 break;
11             }
12         }
13     }
14     return cookieValue;
15 }
16 var csrftoken = getCookie('csrftoken');
17 
18 
19 function csrfSafeMethod(method) {
20   // these HTTP methods do not require CSRF protection
21   return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
22 }
23 
24 $.ajaxSetup({
25   beforeSend: function (xhr, settings) {
26     if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
27       xhr.setRequestHeader("X-CSRFToken", csrftoken);
28     }
29   }
30 });
mysetup.js

csrf相關裝飾器

 1 """
 2 1.網站總體都不校驗csrf,就單單幾個視圖函數須要校驗
 3 2.網站總體都校驗csrf,就單單幾個視圖函數不校驗
 4 """
 5 from django.views.decorators.csrf import csrf_protect,csrf_exempt
 6 from django.utils.decorators import method_decorator
 7 """
 8 csrf_protect  須要校驗
 9     針對csrf_protect符合咱們以前所學的裝飾器的三種玩法
10 csrf_exempt   忽視校驗
11     針對csrf_exempt只能給dispatch方法加纔有效
12 """
13 # @csrf_exempt
14 # @csrf_protect
15 def transfer(request):
16     if request.method == 'POST':
17         username = request.POST.get('username')
18         target_user = request.POST.get('target_user')
19         money = request.POST.get('money')
20         print('%s給%s轉了%s元'%(username,target_user,money))
21     return render(request,'transfer.html')
22 
23 
24 
25 from django.views import View
26 
27 # @method_decorator(csrf_protect,name='post')  # 針對csrf_protect 第二種方式能夠
28 # @method_decorator(csrf_exempt,name='post')  # 針對csrf_exempt 第二種方式不能夠
29 @method_decorator(csrf_exempt,name='dispatch')
30 class MyCsrfToken(View):
31     # @method_decorator(csrf_protect)  # 針對csrf_protect 第三種方式能夠
32     # @method_decorator(csrf_exempt)  # 針對csrf_exempt 第三種方式能夠
33     def dispatch(self, request, *args, **kwargs):
34         return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)
35 
36     def get(self,request):
37         return HttpResponse('get')
38 
39     # @method_decorator(csrf_protect)  # 針對csrf_protect 第一種方式能夠
40     # @method_decorator(csrf_exempt)  # 針對csrf_exempt 第一種方式不能夠
41     def post(self,request):
42         return HttpResponse('post')

補充知識點-補充模塊

1 # 模塊:importlib
2 import importlib
3 res = 'myfile.b'
4 ret = importlib.import_module(res)  # from myfile import b
5 # 該方法最小隻能到py文件名,不能再往下到文件裏邊變量名
6 print(ret)  # <module 'myfile.b' from 'C:\\Users\\Administrator\\PycharmProjects\\day70\\myfile\\b.py'>  

基於django中間件一個重要的編程思想

notify文件夾

__init__.py 文件

 1 import settings
 2 import importlib
 3 
 4 
 5 def send_all(content):
 6     for path_str in settings.NOTIFY_LIST:  # path_str是setting得NOTIFY_LIST列表中一個個的字符串  例如:'notify.email.Email'
 7         module_path, class_name = path_str.rsplit('.', maxsplit=1)
 8         # modult_path = 'notify.email'   class_name = 'Email'
 9         # 1.利用字符串導入模塊
10         module = importlib.import_module(module_path)    # 這句話至關於: from notify import email
11         # 2.利用反射獲取類名
12         cls = getattr(module, class_name)   # 這句話就能夠拿到 Email、QQ、Wechat
13         # 3.生成類的對象
14         obj = cls()
15         # 4.利用鴨子類型直接調用send方法
16         obj.send(content)

email.py、qq.py、msg.py、wechat.py 文件

 1 ----email.py文件----
 2 
 3 class Email(object):
 4     def __init__(self):
 5         pass   # 發送郵箱須要得前期準備工做
 6 
 7     def send(self, content):
 8         print('郵箱通知:%s'%content)
 9 
10 
11 ----msg.py文件----
12 
13 class Msg(object):
14     def __init__(self):
15         pass  # 發送短信須要得前期準備工做
16 
17     def send(self, content):
18         print('短信通知:%s'%content)
19 
20 ----wechat.py文件----
21 
22 class Wechat(object):
23     def __init__(self):
24         pass  # 發送微信須要得前期準備工做
25 
26     def send(self, content):
27         print('微信通知:%s'%content)
28 
29 ----qq.py文件----
30 
31 class QQ(object):
32     def __init__(self):
33         pass  # 發送QQ須要得前期準備工做
34 
35     def send(self, content):
36         print('QQ通知:%s'%content)

settings.py 文件

1 NOTIFY_LIST = [
2     'notify.email.Email',
3     'notify.qq.QQ',
4     'notify.wechat.Wechat',
5     'notify.msg.Msg',
6 ]

start.py 文件

 1 import notify
 2 
 3 notify.send_all('快線上開課了')
 4 
 5 # 執行結果
 6 '''
 7 郵箱通知:快線上開課了
 8 QQ通知:快線上開課了
 9 微信通知:快線上開課了
10 短信通知:快線上開課了
11 '''

 

做業

1 '''
2 今日做業
3 1.整理今日內容至我的博客或筆記中
4 2.本身編寫參考django中間件實現功能可配置插拔式設計體會編程思想
5 '''
相關文章
相關標籤/搜索