動態

詳情 返回 返回

Django學習(3)——中間件 - 動態 詳情

1. Django生命週期

django的生命週期是:前端請求—>nginx—>uwsgi.—>中間件—>url路由---->view視圖—>orm---->拿到數據返回給view---->視圖將數據渲染到模版中拿到字符串---->中間件—>uwsgi---->nginx---->前端渲染。

2. Django中間件

Django 中間件是修改 Django request 或者 response 對象的鈎子,可以理解為是介於 HttpRequest 與 HttpResponse 處理之間的一道處理過程。
瀏覽器從請求到響應的過程中,Django 需要通過很多中間件來處理,可以看如下圖所示:

2.1 內置中間件

  1. django.middleware.security.SecurityMiddleware
做了一些安全處理的中間件。比如設置防禦的請求頭,比如做了http協議轉為https協議的工作等。
  1. django.contrib.sessions.middleware.SessionMiddleware
session中間件。會給request添加一個處理好的session對象。
  1. django.middleware.common.CommonMiddleware
通用中間件,會處理一些URL,比如baidu.com會自動的處理成www.baidu.com。比如/blog/111會處理成/blog/111/自動加上反斜槓。
  1. django.middleware.csrf.CsrfViewMiddleware
保護中間件,在提交表單的時候會必須加入csrf_token,cookie中也會生成一個名叫csrftoken的值,也會在header中加入一個HTTP_X_CSRFTOKEN的值來放置CSRF攻擊。SessionMiddleware必須出現在CsrfMiddleware之前。
  1. django.contrib.auth.middleware.AuthenticationMiddleware
用户授權中間件。會給request添加一個user對象的中間件。該中間件必須在sessionmiddleware後面。
  1. django.contrib.messages.middleware.MessageMiddleware
消息處理中間件。為了在多個模板中可以使用我們返回給模板的變量,並且簡化操作。
  1. django.middleware.clickjacking.XFrameOptionsMiddleware
防止通過瀏覽器頁面跨Frame出現clickjacking(欺騙點擊)攻擊出現。

中間件組件配置在 settings.py 文件的 MIDDLEWARE 選項列表中,配置中的每個字符串選項都是一個類,也就是一箇中間件。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",
]

2.2 自定義中間件

中間件可以定義五個方法,分別是:

process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)

常用的是process_request和process_response,在自己定義中間件時,必須繼承MiddlewareMixin,自定義中間件步驟如下:
①在應用(app1)下創建myMiddleWare.py文件,定義中間件類;

#文件名:myMiddleWare.py
from django.utils.deprecation import MiddlewareMixin

class thCheck(MiddlewareMixin):
    def process_request(self, request):
        print(8848)

    def process_response(self, request, response):
        print(9999)
        return response

②註冊自定義中間件;

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",
    "app1.myMiddleWare.thCheck",  # 自定義的中間件
]

③在app1.views.py中定義視圖函數index:

#文件名:app1.views.py
from django.shortcuts import render
from django.http import HttpResponse

from app1.models import Test

# Create your views here.

# 用作測試的視圖函數
def index(request):
    print("執行index視圖函數...")
    return HttpResponse("index")


def function1(request):
    t = Test(name="func1", age=8)
    t.save()
    return HttpResponse("function1")


def function2(request):
    t = Test(name="func2", age=4)
    t.save()
    return HttpResponse("function2")

④測試:在瀏覽器中訪問http://127.0.0.1:8000/api/app1/index,終端打印如下信息:

3. 典型應用案例

①限制訪問頻率(每分鐘最多訪問10次)
②驗證是否登錄(未登錄用户轉到login界面)

3.1 定義中間件

為了實現限制訪問頻率和驗證登錄兩個功能,分別定義中間件AccessFrequencyMiddleware和LoginRequireMiddleware:

文件名:app1.myMiddleWare.py
import time
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.utils.deprecation import MiddlewareMixin
from django.urls import reverse


class User(object):
    def __init__(self, ip):
        self.ip = ip
        self.reset()

    def reset(self):
        self.first_time = time.time()
        self.counter = 1

# {ip:User()}
user_dict = {}


class AccessFrequencyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        remote_ip = request.META.get('REMOTE_ADDR')
        if remote_ip not in user_dict:
            # 用户首次訪問
            user_dict[remote_ip] = User(remote_ip)
        else:
            user = user_dict.get(remote_ip)
            time_interval = time.time() - user.first_time
            user.counter += 1
            if time_interval < 60 and user.counter > 10:
                user.last_time = time.time()
                user.is_forbidden = True
                return HttpResponse('訪問頻率過高,限制訪問')
            elif time_interval > 60:
                user.reset()
            else:
                pass


class LoginRequireMiddleware(MiddlewareMixin):
    def __init__(self, get_response=None):
        super().__init__(get_response)
        self.get_response = get_response
        self.white_list = ["/login/", "/register/"]  # 白名單
        self.black_list = []  # 黑名單

    def process_request(self, request):
        path = request.path
        print(path, request.user.is_authenticated)
        if request.user.is_authenticated or path in self.white_list:
            return None
        elif path in self.black_list:
            return JsonResponse({"code": 0, "error": "禁止訪問"}, status=403)
        else:
            # viewname 可以是在path()中定義的路由別名name,通過reverse(viewname)函數可以反向查找URL
            return HttpResponseRedirect(reverse('login-view'))

3.2 註冊自定義中間件

文件名:django_study.settings.py
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",
    "app1.myMiddleWare.AccessFrequencyMiddleware",
    "app1.myMiddleWare.LoginRequireMiddleware",
]

3.3 定義登錄視圖函數

在django_study工程路徑下添加views.py程序,編寫登錄視圖函數:

文件名:django_study.views.py
from django.http import HttpResponse


def login(request):
    print("請登錄...")
    return HttpResponse("登錄界面")

3.3 註冊視圖函數對應的URL

文件名:django_study.urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import include

import app1.urls as app1_urls
import app2.urls as app2_urls
from .views import *

urlpatterns = [
    path("admin/", admin.site.urls),
    path("login/", login, name="login-view"),  #視圖函數URL
    path("api/app1/", include(app1_urls)),
    path("api/app2/", include(app2_urls)),
]

3.4 測試

user avatar u_17494575 頭像 u_13137233 頭像 u_17353607 頭像 xingchendahai_68d7dff410962 頭像 chiqingdezhentou 頭像 wanlanqiudeyuechi 頭像 bianchengdandan 頭像 swiftcommunity 頭像 gqkmiss 頭像 algieba 頭像 nixidexuegao 頭像 aipaobudefanqie 頭像
點贊 15 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.