I have a Flask application using flask-restx
and flask-login
. I would like all routes by default to require login, and explicitly define public routes that require no authentication. I have started using decorators following the example given in this question:
Best way to make Flask-Login's login_required the default
It works for function endpoints, but not for restx
resource endpoints.
I have tried adding the function both as a decorator, and using the method_decorators
field. For example:
def public_route(decorated_function):
"""
This is a decorator to specify public endpoints in our flask routes
:param decorated_function:
:return:
"""
decorated_function.is_public = True
return decorated_function
class HelloWorld(ConfigurableResource):
method_decorators = {"get": [public_route]}
@public_route
@api.doc('Welcome message')
def get(self):
return {'hello': 'world'}
And this test passes:
def test_hello_world_is_public():
api = Namespace('health', description='Health related operations')
hello = HelloWorld(api, config=None, logger=None)
is_public_endpoint = getattr(hello.get, 'is_public', False)
assert is_public_endpoint
My challenge is I can't see how to access this attribute in my auth logic:
@app.before_request
def check_route_access():
"""
This function decides whethere access should be granted to an endpoint.
This function runs before all requests.
:return:
"""
is_public_endpoint = getattr(app.view_functions[request.endpoint], 'is_public', False)
if person_authorized_for_path(current_user, request.path, is_public_endpoint):
return
# Otherwise access not granted
return redirect(url_for("auth.index"))
This works for plain function endpoints, but not restx resources.
I understand that restx
is wrapping my resource class in a function so that flask can do dispatch, but I can't figure out how to access the decorator from here. So I have some questions:
Based on this and this, method_decorators
variable should be a list of functions, so you should use it like:
def _perform_auth(method):
is_public_endpoint = getattr(method, 'is_public', False)
# place the validation here
class Resource(flask_restx.Resource):
method_decorators = [_perform_auth]
Is it possible to reach the decorator from the view_function?
Well... it is possible, but I wouldn't recommend it. Here's an example
Is it possible to know whether the endpoint is a restx resource or a plain rest function?
You probably can inspect the func and figure out if it's from restx, maybe looking at __qualname__
, but then again, I`d wouldn't recommend it.
Is there a better way to do what I'm trying to achieve?
I would go one of these solutions:
before_request
decorator for authorizationIf 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