Controle de acesso para Flask-Admin

Meu aplicativo de balão gira em torno da modificação de modelos com base no SQLAlchemy. Portanto, considero o flask-admin um ótimo plug-in, pois mapeia meus modelos SQLA para formulários com visualizações já definidas com uma interface personalizável que é experimentada e testada.

Entendo que o Flask-admin se destina a ser um plugin paraadministradores gerenciar os dados de seus sites. No entanto, não vejo por que não posso usar a FA como uma estrutura para meus usuários CRUD seus dados também.

Para fazer isso, escrevi o seguinte:

class AuthorizationRequiredView(BaseView):

  def get_roles(self):
    raise NotImplemented("Override AuthorizationRequiredView.get_roles not set.")

  def is_accessible(self):
    if not is_authenticated():
      return False
    if not current_user.has_role(*self.get_roles()):
      return False
    return True

  def inaccessible_callback(self, name, **kwargs):
    if not is_authenticated():
      return current_app.user_manager.unauthenticated_view_function()
    if not current_user.has_role(*self.get_roles()):
      return current_app.user_manager.unauthorized_view_function()


class InstructionModelView(DefaultModelView, AuthorizationRequiredView):

  def get_roles(self):
    return ["admin", "member"]

  def get_query(self):
    """Jails the user to only see their instructions.
    """
    base = super(InstructionModelView, self).get_query()
    if current_user.has_role('admin'):
      return base
    else:
      return base.filter(Instruction.user_id == current_user.id)

  @expose('/edit/', methods=('GET', 'POST'))
  def edit_view(self):
    if not current_user.has_role('admin'):
      instruction_id = request.args.get('id', None)
      if instruction_id:
        m = self.get_one(instruction_id)
        if m.user_id != current_user.id:
          return current_app.user_manager.unauthorized_view_function()
    return super(InstructionModelView, self).edit_view()

  @expose('/delete/', methods=('POST',))
  def delete_view(self):
    return_url = get_redirect_target() or self.get_url('.index_view')

    if not self.can_delete:
      return redirect(return_url)

    form = self.delete_form()

    if self.validate_form(form):
      # id is InputRequired()
      id = form.id.data

      model = self.get_one(id)

      if model is None:
        flash(gettext('Record does not exist.'), 'error')
        return redirect(return_url)

      # message is flashed from within delete_model if it fails
      if self.delete_model(model):

        if not current_user.has_role('admin') \
            and model.user_id != current_user.id:
          # Denial: NOT admin AND NOT user_id match
          return current_app.user_manager.unauthorized_view_function()

        flash(gettext('Record was successfully deleted.'), 'success')
        return redirect(return_url)
    else:
      flash_errors(form, message='Failed to delete record. %(error)s')

    return redirect(return_url)

Nota: Estou usando o Flask-User, construído sobre o Flask-Login.

O código acima funciona. No entanto, é difícil abstrair como classe base para outros modelos que eu gostaria de implementar o controle de acesso para operações CRUD e exibições Index / Edit / Detail / Delete.

Principalmente, os problemas são:

o método da API,is_accessible, não fornece a chave primária do modelo. Essa chave é necessária porque, em quase todos os casos, os relacionamentos entre usuários e entidades quase sempre são armazenados por meio de relacionamentos ou diretamente na tabela de modelos (ou seja, ter user_id na tabela de modelos).

algumas visualizações, comodelete_view, não forneça o ID da instância que pode ser recuperado facilmente. Nodelete_view, Tive que copiar a função inteira apenas para adicionar uma linha extra para verificar se ela pertence ao usuário certo.

Certamente alguém pensou sobre esses problemas.

Como devo reescrever isso para algo mais SECO e sustentável?

questionAnswers(0)

yourAnswerToTheQuestion