django 自定義中間件實現訪問頻率限制和IP禁用

由於Http請求是無狀態的,服務端能直知道是那個客戶端的訪問,所以,我們可以利用session技術,記住每個用戶訪問的狀態數據。

  • 在用戶發起請求後,記錄用戶IP, 同時進行每次訪問時間的統計,實現客戶端的訪問頻率限制,IP禁止。
import time
from django.http import HttpResponse

# Create your views here.
VISIT_LIMIT = 20
TIME_INTERVAL = 10
RETRY_TIME = 10
IP_BLACKLIST = ["192.168.1.2", "127.0.0.1"]

class LimitMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # 處理請求前(url匹配前)調用
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        now = time.time()
        print("處理請求前(url匹配前)調用",now)
        request_queue = request.session.get("request_queue", [])
        request_limit = request.session.get("request_limit", 0)
        remot_addr = request.META.get("REMOTE_ADDR", "")

        # 如果請求IP在黑名單中,那麼始終拒絕訪問
        if remot_addr in IP_BLACKLIST:
            return HttpResponse("您的IP已經被封,有問題請聯繫管理員")

        # 如果請求被限制,那麼請等待
        if request_limit:
            time.sleep(1)
            visit_limit =  now - request.session["request_queue"][-1]

            if visit_limit >= request_limit:
                request_limit = 0
                visit_limit = 0
                request.session["request_limit"] = request_limit
                request.session["request_queue"] = []

            return HttpResponse("%d秒後重試"%(request_limit - visit_limit))

        if request_queue == []:
            request_queue.append(now)
            request.session["request_queue"] = request_queue
        else:
            request_queue.append(now)
            request.session["request_queue"] = request_queue

        # TIME_INTERVAL秒內訪問超過VISIT_LIMIT次,則對其訪問進行限制
        if len(request_queue) >= VISIT_LIMIT:
            if request_queue[0] - request_queue[-1] <= TIME_INTERVAL:
                request.session["request_limit"] = RETRY_TIME
                return HttpResponse("訪問過快,%d秒後重試"%(RETRY_TIME))
            else:
                request_queue = []
                request.session["request_queue"] =  request_queue


        response = self.get_response(request)
        # 視圖函數處理後,返回內容給瀏覽器前調用
        # Code to be executed for each request/response after
        # the view is called.

        return response

    # url匹配後視圖函數處理前調用
    def process_view(request, view_func, *view_args, **view_kwargs):
        print("訪問視圖前:process_view")
        # return HttpResponse("你還沒訪問到視圖")

    def process_exception(request, exception, *args):
        print("服務器出錯了....",*args)
        return HttpResponse("服務器出錯了....%")




  • 配置 settings,應爲用到了session技術,所以我們要把自已寫的中間件那在django的session中間件後面,auth之前
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    "frequencylimit.frequencylimitmiddleware.LimitMiddleware",
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章