Django 框架6- 中間件(MiddleWare)

一、什麼是Django中間件?

    1、中間件是Django處理請求/響應的鉤子框架。這是一個輕,低層次的“插件”系統,用於全局改變Django和客戶端的輸入和輸出。

    2、我的理解,給Django加一個裝飾器,客戶端向Django發送請求時,先由中間件處理一下,再決定是否交給Views處理

    3、一般處理哪些任務?請求的日誌、用戶登錄認證、請求地址跳轉、IP地址過濾,等等


二、中間件在哪裏設置?

    project下,project包下的settings.py文件,MIDDLEWARE列表,添加或刪除列表項。


三、多箇中間件的運行方式?

    中間件列表運行從前到後,遇到錯誤停止,返回數據從後到前。類似列表的先進後出。


四、中間件在一次請求中的運行時間點?

    1、Django服務啓動時,中件間初始化

1.png

    2、客戶端請求時,中件間調用

2.png


五、自已怎麼做一箇中間件?

    1、新建一個xxxxxx.py的python文件,可以放在Project任意位置,比如我這裏新建midtest.py存到project根目錄。

    2、在midtest.py裏創建中間件函數或類

from django.utils.deprecation import MiddlewareMixin
# 導入中間件類

class MyMiddleware(MiddlewareMixin):
    # 自定義類繼承中間件類
    def process_request(self,request):
    # 重寫中間件方法
        print("---process_request---")

    3、把創建的中間件添加到settings.py的MIDDLEWARE列表

MIDDLEWARE=["midtest.MYMiddleware",
           ]


六、中間件進階:


        1、自定義中間件的五個方法和執行順序:

            process_request():客戶端請求時執行,然後請求urls.py

            process_view():urls.py之後,views.py之前

            process_template_response():views.py之後

            process_exception():捕獲views.py的錯誤,所以是在views.py之後

            process_response():在exception之後運行

        2、代碼實例

from django.utils.deprecation import MiddlewareMixin
class MyMiddleware(MiddlewareMixin):
    # 例子中列舉了所有方法,但使用的時候可以只用一個
    # 當然也可以通過class MyMid: __init__和__call__來改寫,參考繼承的MiddelwareMixin類的寫法
    
    def process_request(self, request):
    # request參數,客戶端的請求
    # 可以設置驗證登陸、IP阻止列表等功能
    
        # 1、-----通過session驗證登陸-----
        if request.path_info == '/login/':    # 請求login正常執行
            return
        elif not request.session.get('k1', None): # 請求其它頁面判斷未登陸跳轉到login
            return redirect('/login/')
    
        # 2、-----設置拒絕訪問的客戶端IP-----
        refuse_ip=["172.0.0.1"]
        if request.META.get('HTTP_X_FORWARDED_FOR', None):    # 'HTTP_X_FORWARDED_FOR'使用反向代理時,尋找用戶真實IP
            ip = request.META['HTTP_X_FORWARDED_FOR']
        else:
            ip = request.META['REMOTE_ADDR']                  # 如果'HTTP_X_FORWARDED_FOR'不存在則獲取REMOTE_ADDR
        
        if ip in refuse_ip:                                   # 判斷IP是否在拒絕列表裏
            return HttpResponse("幹啥虧心事了,不讓你登陸!")
        
    
    def process_view(self, response, view_func, *args, **kwargs):
        # request客戶端請求
        # view_func 請求的視圖函數
        # *args,**kwargs    請求時附帶的參數
        
        
    def process_exception(self, request, response):
        # 如果views.py函數有報錯,執行
        # request客戶端請求

    

七、CSRF中間件


    跨站請求僞造(英語:Cross-site request forgery),也被稱爲 one-click attack 或者 session riding,通常縮寫爲 CSRF 或者 XSRF, 是一種挾制用戶在當前已登錄的Web應用程序上執行非本意的操作的***方法。跟跨網站腳本(XSS)相比,XSS 利用的是用戶對指定網站的信任,CSRF 利用的是網站對用戶網頁瀏覽器的信任。

    

    解決方法:

    1、檢查HTTP的Referer字段

    2、添加校驗Token

    

    Django的CSRF校驗:

    1、django使用的是添加校驗的Token,

    2、方法一:使用的是中間件'django.middleware.csrf.CsrfViewMiddleware'

          方法二:服務器向客戶端發送一個加密的Token,來進行客戶認證

    3、HTML的From中添加標籤{% csrf_token %}

    4、CSRF源碼:

class CsrfViewMiddleware(MiddlewareMixin):
    def _accept(self, request):
        request.csrf_processing_done = True
        return None
    def _reject(self, request, reason):
        logger.warning(
            'Forbidden (%s): %s', reason, request.path,
            extra={
                'status_code': 403,
                'request': request,
            }
        )
        return _get_failure_view()(request, reason=reason)
    def _get_token(self, request):
        if settings.CSRF_USE_SESSIONS:
            try:
                return request.session.get(CSRF_SESSION_KEY)
            except AttributeError:
                raise ImproperlyConfigured(
                    'CSRF_USE_SESSIONS is enabled, but request.session is not '
                    'set. SessionMiddleware must appear before CsrfViewMiddleware '
                    'in MIDDLEWARE%s.' % ('_CLASSES' if settings.MIDDLEWARE is None else '')
                )
        else:
            try:
                cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME]
            except KeyError:
                return None
            csrf_token = _sanitize_token(cookie_token)
            if csrf_token != cookie_token:
                # Cookie token needed to be replaced;
                # the cookie needs to be reset.
                request.csrf_cookie_needs_reset = True
            return csrf_token
    def _set_token(self, request, response):
        if settings.CSRF_USE_SESSIONS:
            request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
        else:
            response.set_cookie(
                settings.CSRF_COOKIE_NAME,
                request.META['CSRF_COOKIE'],
                max_age=settings.CSRF_COOKIE_AGE,
                domain=settings.CSRF_COOKIE_DOMAIN,
                path=settings.CSRF_COOKIE_PATH,
                secure=settings.CSRF_COOKIE_SECURE,
                httponly=settings.CSRF_COOKIE_HTTPONLY,
            )
            patch_vary_headers(response, ('Cookie',))
    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):
        if getattr(request, 'csrf_processing_done', False):
            return None
        if getattr(callback, 'csrf_exempt', False):
            return None
        if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
            if getattr(request, '_dont_enforce_csrf_checks', False):
                return self._accept(request)
            if request.is_secure():
                referer = force_text(
                    request.META.get('HTTP_REFERER'),
                    strings_only=True,
                    errors='replace'
                )
                if referer is None:
                    return self._reject(request, REASON_NO_REFERER)
                referer = urlparse(referer)
                if '' in (referer.scheme, referer.netloc):
                    return self._reject(request, REASON_MALFORMED_REFERER)
                if referer.scheme != 'https':
                    return self._reject(request, REASON_INSECURE_REFERER)
                good_referer = (
                    settings.SESSION_COOKIE_DOMAIN
                    if settings.CSRF_USE_SESSIONS
                    else settings.CSRF_COOKIE_DOMAIN
                )
                if good_referer is not None:
                    server_port = request.get_port()
                    if server_port not in ('443', '80'):
                        good_referer = '%s:%s' % (good_referer, server_port)
                else:
                    good_referer = request.get_host()
                good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
                good_hosts.append(good_referer)
                if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
                    reason = REASON_BAD_REFERER % referer.geturl()
                    return self._reject(request, reason)
            csrf_token = request.META.get('CSRF_COOKIE')
            if csrf_token is None:
                return self._reject(request, REASON_NO_CSRF_COOKIE)
            request_csrf_token = ""
            if request.method == "POST":
                try:
                    request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
                except IOError:
                    pass
            if request_csrf_token == "":
                request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
            request_csrf_token = _sanitize_token(request_csrf_token)
            if not _compare_salted_tokens(request_csrf_token, csrf_token):
                return self._reject(request, REASON_BAD_TOKEN)
        return self._accept(request)
    def process_response(self, request, response):
        if not getattr(request, 'csrf_cookie_needs_reset', False):
            if getattr(response, 'csrf_cookie_set', False):
                return response
        if not request.META.get("CSRF_COOKIE_USED", False):
            return response
        self._set_token(request, response)
        response.csrf_cookie_set = True
        return response





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章