day70-django中間件

django中間件

"""
django中間件是django的門戶
1.請求來的時候須要先通過中間件才能到達真正的django後端
2.響應走的時候最後也須要通過中間件才能發送出去

django自帶七個中間件
"""
django請求生命週期流程圖

研究django中間件代碼規律
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',
]

class SessionMiddleware(MiddlewareMixin):
    def process_request(self, request):
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
        request.session = self.SessionStore(session_key)
    def process_response(self, request, response):
        return response
      
class CsrfViewMiddleware(MiddlewareMixin):
      def process_request(self, request):
        csrf_token = self._get_token(request)
        if csrf_token is not None:
            # Use same token next time.
            request.META['CSRF_COOKIE'] = csrf_token
    def process_view(self, request, callback, callback_args, callback_kwargs):
        return self._accept(request)

    def process_response(self, request, response):
        return response
      
class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        request.user = SimpleLazyObject(lambda: get_user(request))
"""
django支持程序員自定義中間件而且暴露給程序員五個能夠自定義的方法
    1.必須掌握
        process_request
        
        process_response
    2.瞭解便可
        process_view
            
        process_template_response
        
        process_exception
"""

如何自定義中間件

"""
1.在項目名或者應用名下建立一個任意名稱的文件夾
2.在該文件夾內建立一個任意名稱的py文件
3.在該py文件內須要書寫類(這個類必須繼承MiddlewareMixin)
    而後在這個類裏面就能夠自定義五個方法了
    (這五個方法並非所有都須要書寫,用幾個寫幾個)
4.須要將類的路徑以字符串的形式註冊到配置文件中才能生效
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',
    '你本身寫的中間件的路徑2',
    '你本身寫的中間件的路徑3',
]

"""
"""
1.必須掌握
        process_request 
            1.請求來的時候須要通過每個中間件裏面的process_request方法
            結果的順序是按照配置文件中註冊的中間件從上往下的順序依次執行
            2.若是中間件裏面沒有定義該方法,那麼直接跳過執行下一個中間件
            3.若是該方法返回了HttpResponse對象,那麼請求將再也不繼續日後執行
            而是直接原路返回(校驗失敗不容許訪問...)
            process_request方法就是用來作全局相關的全部限制功能
            
        process_response
            1.響應走的時候須要結果每個中間件裏面的process_response方法
            該方法有兩個額外的參數request,response
            2.該方法必須返回一個HttpResponse對象
                1.默認返回的就是形參response
                2.你也能夠本身返回本身的
            3.順序是按照配置文件中註冊了的中間件從下往上依次通過
                若是你沒有定義的話 直接跳過執行下一個
        
        研究若是在第一個process_request方法就已經返回了HttpResponse對象,那麼響應走的時候是通過全部的中間件裏面的process_response仍是有其餘狀況
        是其餘狀況
            就是會直接走同級別的process_reponse返回
        
        flask框架也有一箇中間件可是它的規律
            只要返回數據了就必須通過全部中間件裏面的相似於process_reponse方法
            
            
2.瞭解便可
        process_view
            路由匹配成功以後執行視圖函數以前,會自動執行中間件裏面的該放法
            順序是按照配置文件中註冊的中間件從上往下的順序依次執行
            
        process_template_response
            返回的HttpResponse對象有render屬性的時候纔會觸發
            順序是按照配置文件中註冊了的中間件從下往上依次通過
            
        process_exception
            當視圖函數中出現異常的狀況下觸發
            順序是按照配置文件中註冊了的中間件從下往上依次通過
"""
    

csrf跨站請求僞造

"""
釣魚網站
    我搭建一個跟正規網站如出一轍的界面(中國銀行)
    用戶不當心進入到了咱們的網站,用戶給某我的打錢
    打錢的操做確確實實是提交給了中國銀行的系統,用戶的錢也確確實實減小了
    可是惟一不一樣的時候打錢的帳戶不適用戶想要打的帳戶變成了一個莫名其妙的帳戶

大學英語四六級
    考以前須要學生本身網站登錄繳費

內部本質
    咱們在釣魚網站的頁面 針對對方帳戶 只給用戶提供一個沒有name屬性的普通input框
    而後咱們在內部隱藏一個已經寫好name和value的input框

如何規避上述問題
    csrf跨站請求僞造校驗
        網站在給用戶返回一個具備提交數據功能頁面的時候會給這個頁面加一個惟一標識
        當這個頁面朝後端發送post請求的時候 個人後端會先校驗惟一標識,若是惟一標識不對直接拒絕(403 forbbiden)若是成功則正常執行    
"""

如何符合校驗

# form表單如何符合校驗
<form action="" method="post">
    {% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>target_user:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
</form>

# ajax如何符合校驗
// 第一種 利用標籤查找獲取頁面上的隨機字符串
{#data:{"username":'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#}
// 第二種 利用模版語法提供的快捷書寫
{#data:{"username":'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
// 第三種 通用方式直接拷貝js代碼並應用到本身的html頁面上便可
data:{"username":'jason'}
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);
    }
  }
});

csrf相關裝飾器

"""
1.網站總體都不校驗csrf,就單單幾個視圖函數須要校驗
2.網站總體都校驗csrf,就單單幾個視圖函數不校驗
"""
from django.views.decorators.csrf import csrf_protect,csrf_exempt
from django.utils.decorators import method_decorator
"""
csrf_protect  須要校驗
    針對csrf_protect符合咱們以前所學的裝飾器的三種玩法
csrf_exempt   忽視校驗
    針對csrf_exempt只能給dispatch方法加纔有效
"""
# @csrf_exempt
# @csrf_protect
def transfer(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        target_user = request.POST.get('target_user')
        money = request.POST.get('money')
        print('%s給%s轉了%s元'%(username,target_user,money))
    return render(request,'transfer.html')



from django.views import View

# @method_decorator(csrf_protect,name='post')  # 針對csrf_protect 第二種方式能夠
# @method_decorator(csrf_exempt,name='post')  # 針對csrf_exempt 第二種方式不能夠
@method_decorator(csrf_exempt,name='dispatch')
class MyCsrfToken(View):
    # @method_decorator(csrf_protect)  # 針對csrf_protect 第三種方式能夠
    # @method_decorator(csrf_exempt)  # 針對csrf_exempt 第三種方式能夠
    def dispatch(self, request, *args, **kwargs):
        return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)

    def get(self,request):
        return HttpResponse('get')

    # @method_decorator(csrf_protect)  # 針對csrf_protect 第一種方式能夠
    # @method_decorator(csrf_exempt)  # 針對csrf_exempt 第一種方式不能夠
    def post(self,request):
        return HttpResponse('post')

補充知識點

# 模塊:importlib
import importlib
res = 'myfile.b'
ret = importlib.import_module(res)  # from myfile import b
# 該方法最小隻能到py文件名
print(ret)

重要思想

import settings
import importlib


def send_all(content):
    for path_str in settings.NOTIFY_LIST:  #'notify.email.Email'
        module_path,class_name = path_str.rsplit('.',maxsplit=1)
        # module_path = 'notify.email'  class_name = 'Email'
        # 1 利用字符串導入模塊
        module = importlib.import_module(module_path)  # from notify import email
        # 2 利用反射獲取類名
        cls = getattr(module,class_name)  # Email、QQ、Wechat
        # 3 生成類的對象
        obj = cls()
        # 4 利用鴨子類型直接調用send方法
        obj.send(content)
相關文章
相關標籤/搜索