4

I am creating a Flask-Admin app that requires checking permissions to View, Edit & Delete certain rows in a table.

i.e, I would like to:

  • List only rows where the User ID matches the Owner ID of the row
  • Let the user Create a row if they have a certain Role
  • Only let user Edit a row if they have a certain Role

I can think of overriding methods query(), on_model_change(), etc to check an Edit permit, but:

  • A user could still view the row by changing the URL to display the Edit screen
  • I don't know how to restrict a WTForms one-to-many edit list to only allowed items

How may I achieve this?

Rafael
  • 1,018
  • 1
  • 10
  • 18
  • 1
    Have you seen the [**Flask-RBAC**](https://flask-rbac.readthedocs.org/en/latest/) extension which gives a role based access control? – doru Jul 27 '15 at 21:28
  • I didn't know Flask-RBAC, but I don't see how it gives any advantage over Flask-Security or Flask-Principal in solving this problem. – Rafael Jul 28 '15 at 01:06

1 Answers1

3

A quick and dirty solution to my own problem:

1. Create a generic function to check ownership in the ModelView class

def is_owned(self, id):
    model = db.session.query(self.model).filter(self.model.id == id).all()
    if len(model) == 0:
        return False
    else:
        model = model[0]
    if model.user_id == current_user.id:
        return True
    return False

2. Override ModelView's on_model_change, on_form_prefill, on_model_delete, get_query and get_count_query methods to check for ownership (user_id = current_user.id):

def on_model_change(self, form, model, is_created):
    if not self.is_owned(model.id):
        abort(403)

def on_form_prefill(self, form, id):
    if not self.is_owned(id):
        abort(403)

def on_model_delete(self, model):
    if not self.is_owned(model.id):
        abort(403)

def get_query(self):
    return super(Tables, self).get_query().filter(self.model.user_id == current_user.id)

def get_count_query(self):
    return super(Tables,self).get_count_query().filter(self.model.user_id == current_user.id)
Rafael
  • 1,018
  • 1
  • 10
  • 18