Search code examples
pythonflaskflask-security

flask-security roles_required with pluggable views


I'm trying to require a role to access a view that I've defined as a MethodView. However, I can't seem to get the route to be named correctly.

If I simply require logging in with a decorator everything works:

activities = Blueprint("activities", __name__, url_prefix="/activities")

class ActivitiesView(MethodView):
    def get():
        pass

    def post():
        pass

view = login_required(ActivitiesView.as_view("activities"))
activities.add_url_rule('/', view_func=view)

I get the desired route name, i.e. activities.activities:

>>> current_app.url_map
Map([...
 <Rule '/activities/' (HEAD, POST, OPTIONS, GET) -> activities.activities>,
...])

However, when I try to use roles_required, the name of the route is mangled and the POST method is no longer listed:

view = roles_required("experimenter", ActivitiesView.as_view("activities"))
activities.add_url_rule('/', view_func=view)

>>> current_app.url_map
Map([...
 <Rule '/activities/' (HEAD, OPTIONS, GET) -> activities.wrapper>,
...])

Switching the arguments to add_url_rule doesn't change anything. How can I use roles_required without messing up the route name?

Doing this fixes the route name, but not the missing POST method:

view = roles_required("experimenter", endpoint="activities", ActivitiesView.as_view("activities"))
activities.add_url_rule('/', view_func=view)

Solution

  • The solution is to call the decorator:

    view = roles_required("experimenter")(ActivitiesView.as_view("activities"))
    activities.add_url_rule('/', view_func=view)
    

    Alternatively:

    decorators = [roles_required("experimenter")]
    

    Thanks to this article:

    http://scottlobdell.me/2015/04/decorators-arguments-python/