########django-基於中間件寫一個限制頻繁登錄########

django-基於中間件寫一個限制頻繁登錄前端

額額,標題已經很醒目了,經過中間件去實現,其餘方法也能夠實現python

瀏覽器前端傳來的請求,必須經過中間件,才能到後面路由,視圖函數,因此咱們在中間件那裏作一層處理,
咱們還須要知道是哪一個ip,在何時,請求了幾回,這些數據是要知道,而且記錄下來,因此我建立了一個
表,來存放這些信息數據數據庫

models文件:django

class Host_info(models.Model):
        host = models.CharField(max_length=32)
        count = models.IntegerField()
        start_time = models.DateTimeField()
        is_lock = models.CharField(max_length=32,default='2')
host:記錄主機ip
count:記錄請求的次數
start_time:記錄請求的時間
is_lock:記錄該ip的狀態,默認爲2   2表明未鎖定,1表明鎖定

接下來就是自定義中間件了,並寫process_request方法,咱們只對請求作處理,我先貼代碼,最後寫我遇到的一些問題瀏覽器

mymiddleware文件(我自定義的中間件):app

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
from app01 import models
import datetime


class Md1(MiddlewareMixin):
    def process_request(self, request):
        url = request.path
        if url.startswith('/favicon.ico'):
            return HttpResponse


class Md2(MiddlewareMixin):
    def process_request(self, request):
        now_time = datetime.datetime.now()
        host = request.META.get('REMOTE_ADDR')
        ret = models.Host_info.objects.filter(host=host).first()
        if ret:
            aa = now_time - ret.start_time
            if aa.seconds >= 60:
                ret.count = 1
                ret.start_time = now_time
                ret.is_lock = '2'
                ret.save()
                return None
            if aa.seconds < 60 and ret.is_lock == '1':
                return HttpResponse('登錄次數頻繁,一分鐘後再試')

            if ret.count < 4 and ret.is_lock == '2':
                if ret.count == 2:
                    ret.is_lock = '1'
                    ret.count = 0
                    ret.save()
                else:
                    ret.count += 1
                    ret.start_time = now_time
                    ret.save()
                return None

        else:
            models.Host_info.objects.create(host=host, start_time=now_time, count=1)
            return None

settings文件:
添加兩行代碼在MIDDLEWARE列表中:
'mymiddleware.Md1',
'mymiddleware.Md2',函數

並配置下面兩句,緣由後面會說
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False測試

遇到兩個問題:url

問題一:就是datetime,也就是時間分區問題,由於我數據表中須要保存到該ip訪問的時間,存的時候存的是datetime對象
,可是我從數據庫中取出來這個時間,進行比較會報出錯誤,錯誤類型忘記了,我就打印了從數據庫中取出的時間數據,
發現,這個時間帶着時區,而我datetime.datetime.now()的時間是本機時間,根本不能相減,相比較。網上收索才
知道django默認是有時間分區的,TIME_ZONE = 'UTC',USE_TZ = True,這兩句。
解決方式:在setting文件中將上面那兩句修改成TIME_ZONE = 'Asia/Shanghai',USE_TZ = False。這樣就解決了。
在django中但凡出現時間的話,這個地方須要注意下。code

問題二:額額這個問題,我在寫的時候出現過,可是今天測試沒那個問題,反正寫上吧。我以前的錯誤就是我發出一個請求,首先
第一個請求就是訪問到url,接着第二個請求就是發出favicon.ico這種相似的,請求ico這個。以這個狀況來講問題吧,
你雖然在瀏覽器只發出一個請求,可是響應過來的網頁,裏面能夠還有其餘請求,因此這中狀況須要考慮到。
解決方式:我在對用戶ip作限制以前,加一箇中間件,過濾掉其它的請求。,也就是上面的MD1。

代碼其實很簡單,主要是邏輯處理,你是怎麼想就用代碼去實現。

對了,這裏的數據存儲,你能夠定義一個變量去存放存這些信息(也就是我數據表存放的這個)

這裏惟一值得注意的就是時間了,你要很清楚知道時區這個問題。

補充·

補充一點,datetime的一個用法
例子中我用到datetime對象之間相減,取差多少秒,也就是這句
    aa = now_time - ret.start_time
    aa.seconds  # 取到相差多少秒
    這裏的aa是datetime.timedelta類型
相關文章
相關標籤/搜索