Flask-Admin的访问控制

时间:2017-10-24 15:09:19

标签: python flask flask-admin

我的烧瓶应用程序围绕修改基于SQLAlchemy的模型。因此,我发现flask-admin是一个很棒的插件,因为它将我的SQLA模型映射到已经使用经过试验和测试的可自定义界面定义的视图的表单。

据我所知,Flask-admin旨在成为管理其网站数据的管理员的插件。但是,我不明白为什么我不能使用FA作为我的用户CRUD他们的数据的框架。

为此,我写了以下内容:

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)

注意:我使用的是Flask-User,它建立在Flask-Login之上。

上面的代码有效。但是,很难将其抽象为其他模型的基类,我希望为CRUD操作和索引/编辑/详细信息/删除视图实现访问控制。

主要是问题是:

  1. API方法is_accessible不提供模型的主键。需要此密钥是因为在几乎所有情况下,用户和实体之间的关系几乎总是通过关系或直接存储在模型表中(即在模型表中具有user_id)。

  2. 某些视图(例如delete_view)不提供可以轻松检索的实例ID。在delete_view中,我不得不复制整个函数,只是添加一行以检查它是否属于正确的用户。

  3. 当然有人考虑过这些问题。

    我应该如何将其重写为更干燥和可维护的内容?

0 个答案:

没有答案