I am trying to build a RESTful API app with flask_restful
, flask_jwt_extended
for user authorization and flask_limiter
to limit the quota of a user at 6/minute. My toy/testing code follows (no actual authorization schemes have been implemented yet):
from flask import Flask, make_response
from flask_restful import Api, Resource
from flask_limiter import Limiter
from werkzeug.exceptions import HTTPException
from flask_jwt_extended import jwt_required, create_access_token, JWTManager, get_jwt_identity
# custom HTTP exception
class OutOfQuota(HTTPException):
code = 402
name = 'Out Of Quota'
app = Flask(__name__)
limiter = Limiter(app, key_func=get_jwt_identity)
api = Api(prefix='')
class Token(Resource):
def get(self, user):
return make_response({'token': create_access_token(identity=user)})
class Test(Resource):
@jwt_required
@limiter.limit('6/minute')
def get(self):
return make_response({'message': f'OK {get_jwt_identity()}'})
api.add_resource(Token, '/token/<string:user>')
api.add_resource(Test, '/test')
api.init_app(app)
# custom error handler (change "Payment Required" to "Out Of Quota" HTTP status
@app.errorhandler(429)
def ratelimit_handler(e):
return OutOfQuota(f'quota limit exceeded: {e.description}')
jwt = JWTManager(app)
app.config['JWT_SECRET_KEY'] = 'nothing-fancy-for-now'
if __name__ == '__main__':
app.run(host='localhost', port=8080)
The endpoint /token
generates a JWT token for the user, with their username stored inside as the JWT identity. When the /test
endpoint is accessed with this token, I want to check how many times this specific user (i.e. this specific identity) has accessed this endpoint, hence the usage of get_jwt_identity
as the key_func
of the Limiter
.
The problem is that I do not have any limit when I access the /test
endpoint when I run the above code; I can access it as many times as I want, as fast as I want. Am I missing something here?
I had the similar issue and found a solution that seems to work. Flask-Restful
does things a little differently. It creates pluggable views. There's a section in Flask-Limiter
docs about this particular case - https://flask-limiter.readthedocs.io/en/stable/#using-flask-pluggable-views
class Test(Resource):
decorators = [limiter.limit("5/minute")]
def get(self):
...
Instead of providing the decorator via @limiter.limit
, we need to provide it this way.
I also had an issue about where to get the reference of limiter
from. In some base directory, you can implement this and import in your class.
from flask import Flask
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
_app = Flask(__name__)
limiter = Limiter(
_app,
key_func=get_remote_address
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With