我正在建立一个带有flask和flask_limiter的API端点,我遇到了一个问题。我的目标是在一个端点上对客户端IP地址进行速率限制,以及客户端提供的API密钥(可通过烧瓶的“请求”模块访问)。
IP地址限制器很重要,因为我想防止暴力攻击,而API密钥限制器仅仅是出于商业原因。我已经建立了两个速率限制器,并且它们独立工作(即我可以限制IP地址或提供的API密钥),但我无法同时在端点上运行。到目前为止我尝试过的一个例子:
from flask import Flask, request
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
app = Flask(__name__)
ip_limiter = Limiter(app, key_func=get_remote_address)
get_api_key = lambda : request.args.get('apikey')
api_key_limiter = Limiter(app, key_func=get_api_key)
@app.route('/theEndpoint')
@ip_limiter.limit('some_limit_here')
@api_key_limiter.limit('other_limit_here')
def theEndpointFunction(...):
.......
在单个软件包(即flask_limiter)中实现所有速率限制会很不错,但到目前为止,我认为在多个密钥上实现速率限制的唯一方法是切换到像redis这样的东西。
有关使用flask_limiter实现多键速率限制的方法的任何线索?
答案 0 :(得分:0)
如果有人有兴趣,我决定切换到Redis来实现我的双键速率限制。解决方案是这样的:
class RateLimit(object):
def __init__(self, key, max_requests, seconds):
self.reset = int(time.time()) + seconds
self.key = key
self.max_requests = max_requests
self.seconds = seconds
p = redis.pipeline()
p.incr(self.key)
p.expireat(self.key, self.reset)
self.current = min(p.execute()[0], max_requests)
remaining = property(lambda x: x.max_requests - x.current)
over_limit = property(lambda x: x.current >= x.max_requests)
def get_view_rate_limit():
return getattr(g, '_view_rate_limit', None)
def over_limit(limit):
#formatting a JSON response
response = {"result": "Max number of requests exceeded",
"status": False}
response = jsonify(response)
response.status_code = 400
return response
def ratelimit(max_requests, seconds, key_func, over_limit=over_limit):
def decorator(f):
def rate_limited(*args, **kwargs):
key = key_func()
rlimit = RateLimit(key, max_requests, seconds)
g._view_rate_limit = rlimit
if over_limit is not None and rlimit.over_limit:
return over_limit(rlimit)
return f(*args, **kwargs)
return update_wrapper(rate_limited, f)
return decorator
RATE_LIMIT_FUNCS = {'apikey': lambda: request.args.get('apikey'),
'ip': lambda: get_remote_address}
然后装饰烧瓶终点:
@app.route('/theEndpoint')
@ratelimit(max_requests=5, seconds=300, key_func=RATE_LIMIT_FUNCS['apikey'])
@ratelimit(max_requests=15, seconds=300, key_func=RATE_LIMIT_FUNCS['ip'])
def theEndpointFunction():
....