Flask自定义角色包装器给出“ AssertionError:视图函数映射正在覆盖现有的端点函数:运行”

时间:2019-07-03 21:52:23

标签: python flask wrapper rbac flask-login

我正在尝试创建一个角色包装器,这将允许我为不同用户限制某些页面和内容。我已经实现了用于检查此问题的方法,但是用于实现此目的的包装器/装饰器有时会失败,有时甚至不会,而且我也不知道可能是什么原因。

我一直在寻找导致此问题的原因的最终原因,但是不幸的是,与我提出的大多数其他搜索一样,Flask的回溯并没有给出最终的原因或解决方案。

我正在使用Flask-Login,Flask-Migrate和Flask-SQLAlchemy来管理我的Web应用程序,我研究了各种应用RBAC的方法,但是它们都需要对我的数据库模型进行看似复杂的更改,并且觉得从长远来看,我的方法更有可能工作。

这是我的简化代码(如果需要,我可以提供完整的应用程序)。下面是调试器的完整回溯。

谢谢。

routes.py

def require_role(roles=["User"]):
    def wrap(func):
        def run(*args, **kwargs):
            if current_user.is_authenticated:
                if current_user.has_roles(roles):
                    return func(*args, **kwargs)
            return abort(401)
        return run
    return wrap

@app.route('/hidden<id>/history')
@login_required
@require_role(roles=['Admin'])
def hidden_history(id):
    if not validate_id(id):
        return '<span style="color: red;">error:</span> bad id'
    return render_template('hidden_history.html')

@app.route('/hidden<id>/help')
@login_required
def hidden_help(id):
    if not validate_id(id):
        return '<span style="color: red;">error:</span> bad id'
    return render_template('hidden_help.html')

@app.route('/hidden<id>/')
@login_required
@require_role(roles=['Hidden'])
def hidden(id):
    if not validate_id(id):
        return '<span style="color: red;">error:</span> bad id'
    # ...
    return render_template('hidden.html')

Traceback (most recent call last)

Traceback (most recent call last):
  File "A:\Programming\Python\Flask\xevion.dev\wsgi.py", line 1, in <module>
    from app import app, db
  File "A:\Programming\Python\Flask\xevion.dev\app\__init__.py", line 18, in <module>
    from app import routes, models
  File "A:\Programming\Python\Flask\xevion.dev\app\routes.py", line 143, in <module>
    @require_role(roles=['Hidden'])
  File "c:\users\xevion\appdata\local\programs\python\python36\lib\site-packages\flask\app.py", line 1251, in decorator
    self.add_url_rule(rule, endpoint, f, **options)
  File "c:\users\xevion\appdata\local\programs\python\python36\lib\site-packages\flask\app.py", line 67, in wrapper_func
    return f(self, *args, **kwargs)
  File "c:\users\xevion\appdata\local\programs\python\python36\lib\site-packages\flask\app.py", line 1222, in add_url_rule
    'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint function: run

编辑:现在,我意识到当对包装函数的调用不止一个时,它不起作用。怎么会来?

2 个答案:

答案 0 :(得分:0)

乍看之下,它似乎与run装饰器(docs)中的require_role函数发生冲突:

def require_role(roles=["User"]):
    def wrap(func):
        def wrapped_func(*args, **kwargs):
            ...

答案 1 :(得分:0)

因此,为了解决过去两个小时困扰我的问题,我研究了flask_login模块的实际工作方式,经过一番调查后,我发现他们使用了从functools导入,称为wraps

我导入了该文件,复制了flask_login基本上是如何实现的,我的应用现在可以正常工作了。

def require_role(roles=["User"]):
    def wrap(func):
        @wraps(func)
        def decorated_view(*args, **kwargs):
            if current_user.is_authenticated:
                if current_user.has_roles(roles):
                    return func(*args, **kwargs)
            return abort(401)
        return decorated_view
    return wrap

flask_login/utils.py#L264