2017-11-13 6 views
1

플라스크 및 flask_limiter를 사용하여 API 끝점을 만드는 중입니다. 문제가 발생합니다. 내 목표는 클라이언트 IP 주소뿐만 아니라 단일 끝점에서 클라이언트가 제공하는 API 키 (플라스크의 "요청"모듈을 통해 액세스 할 수 있음)의 속도를 제한하는 것입니다.Flask Limiter - 단일 끝점에 둘 이상의 key_func 사용

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

관심이있는 사람이라면 필자는 이중 키 제한 속도를 구현하기 위해 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(): 
    ....