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',
]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章