我的烧瓶应用程序围绕修改基于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操作和索引/编辑/详细信息/删除视图实现访问控制。
主要是问题是:
API方法is_accessible
不提供模型的主键。需要此密钥是因为在几乎所有情况下,用户和实体之间的关系几乎总是通过关系或直接存储在模型表中(即在模型表中具有user_id)。
某些视图(例如delete_view
)不提供可以轻松检索的实例ID。在delete_view
中,我不得不复制整个函数,只是添加一行以检查它是否属于正确的用户。
当然有人考虑过这些问题。