不同方式实现IP访问限制

要实现IP访问限制,有很多种方法。根据不同的使用场景大致可以分为权限限制爬虫限制。顾名思义权限限制就是根据权限设定特定的IP能够访问,爬虫限制是为了应对爬虫短时间内大量的访问而进行的限制。

权限限制

权限限制的实现方式可分为三种,分别是linux防火墙实现、nginx配置实现代码中实现

linux防火墙实现:

#阻止所有IP访问
iptables -A INPUT -s 0.0.0.0/0 -p tcp --dport 80 -j DROP
#然后再添加白名单
iptables -A INPUT -s 1.2.3.4 -p tcp --dport 80 -j ACCEPT
###############或者###########
iptables -A INPUT -s 2.3.4.5 -p tcp -j ACCEPT

nginx配置实现

##对应的location添加指定规则
location / {
    allow 132.23.22.185;
    deny all;
}

代码实现:

爬虫限制

爬虫的限制基本上都是对ip的访问频率进行限制,一般都是在代码中实现,以python为例,django进行开发时一般都会自己写一个中间件,对前端发过来的请求进行判断,下面举例说明:

方式一:REST_FRAMEWORK配置(对使用rest_framework框架的项目来说,可以使用框架对ip的访问频率进行限制)

# 仅包含相关配置部分代码

# settings.py
REST_FRAMEWORK = {
     'DEFAULT_THROTTLE_CLASSES': (
         # 开启匿名用户接口请求频率限制
         'rest_framework.throttling.AnonRateThrottle',
         # 开启授权用户接口请求频率限制
         'rest_framework.throttling.UserRateThrottle'
     ),
     'DEFAULT_THROTTLE_RATES': {
         # 频率限制有second, minute, hour, day
         # 匿名用户请求频率
         'anon': '30/second',
         # 授权用户请求频率
         'user': '30/second'
     }
}


# views.py
class IndexView(APIView):
	throttle_class = (AnonRateThrottle, UserRateThrottle)
	...

方式二:利用Django的中间件来进行限制

1、使用session

'''
将ip访问的每次时间添加到session里面,在session里面维护一个长度为2的时间队列,判断当前访问的时间和第一访问的时间差
'''
import time
from django.utils.deprecation import MiddlewareMixin
MAX_REQUEST_PER_SECOND=2 #每秒访问次数

class RequestBlockingMiddleware(MiddlewareMixin):
    def process_request(self,request):
        now=time.time()
        request_queue = request.session.get('request_queue',[])
        if len(request_queue) < MAX_REQUEST_PER_SECOND:
            request_queue.append(now)
            request.session['request_queue']=request_queue
        else:
            time0=request_queue[0]
            if (now-time0)<1:
                time.sleep(5)
            request_queue.append(time.time())
            request.session['request_queue']=request_queue[1:]

#启用RequestBlocking中间件
IDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'common.middleware.RequestBlockingMiddleware',  #在sessions之后,auth之前
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

2、使用表单

'''浏览器前端传来的请求,必须通过中间件,才能到后面路由,视图函数,所以我们在中间件那里做一层处理. 我们还需要知道是哪个ip,在什么时候,请求了几次,这些数据是要知道,并且记录下来,所以我创建了一个表,来存放这些信息数据'''

models文件:
class Host_info(models.Model):
    host = models.CharField(max_length=32)  #记录主机ip
    count = models.IntegerField()          #记录请求的次数
    start_time = models.DateTimeField()    #记录请求的时间
    is_lock = models.CharField(max_length=32,default='2')#记录该ip的状态,默认为2   2代表未锁定,1代表锁定
'''接下来就是自定义中间件了,并写process_request方法,我们只对请求做处理,先贴代码,最后写遇到的一些问题. mymiddleware文件(我自定义的中间件):'''
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

'''遇到两个问题:

问题一:就是datetime,也就是时间分区问题,因为我数据表中需要保存到该ip访问的时间,存的时候存的是datetime对象 ,但是我从数据库中取出来这个时间,进行比较会报出错误,错误类型忘记了,我就打印了从数据库中取出的时间数据, 发现,这个时间带着时区,而我datetime.datetime.now()的时间是本机时间,根本不能相减,相比较。网上收索才 知道django默认是有时间分区的,TIME_ZONE = 'UTC',USE_TZ = True,这两句。
解决方式:在setting文件中将上面那两句修改为TIME_ZONE = 'Asia/Shanghai',USE_TZ = False。这样就解决了。在django中但凡出现时间的话,这个地方需要注意下。

问题二:额额这个问题,我在写的时候出现过,但是今天测试没那个问题,反正写上吧。我之前的错误就是我发出一个请求,首先第一个请求就是访问到url,接着第二个请求就是发出favicon.ico这种类似的,请求ico这个。以这个情况来说问题吧,你虽然在浏览器只发出一个请求,但是响应过来的网页,里面可以还有其他请求,所以这中情况需要考虑到。
解决方式:我在对用户ip做限制之前,加一个中间件,过滤掉其它的请求。,也就是上面的MD1。


补充一点,datetime的一个用法
例子中我用到datetime对象之间相减,取差多少秒,也就是这句
aa = now_time - ret.start_time
aa.seconds  # 取到相差多少秒
这里的aa是datetime.timedelta类型'''

3、使用redis

def iplimit_redis(request):
    ip_addr = request.META.get("REMOTE_ADDR")
    try:
        redis_conn = get_redis_connection("default")
        ip_obj = redis_conn.get("ip_%s" % ip_addr)
        if ip_obj:
            data = {
                "code": "li-001",
                "message": "10秒之内只能请求一次"
            }
            return JsonResponse(data)
        else:
            try:
                redis_conn.setex("ip_%s" % ip_addr, 10, ip_addr)
                data = {
                    "code": "li-000",
                    "message": "新建用户成功",
                    "ip": ip_addr,
                }
            except:
                data = {
                    "code": "li-002",
                    "message": "新建异常"
                }
            return JsonResponse(data)
    except:
        data = {
            "code": "li-002",
            "message": "查询id异常"
        }
        return JsonResponse(data)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值