Flask Custom Role Wrapper дает «AssertionError: отображение функции представления перезаписывает существующую функцию конечной точки: run» - PullRequest
0 голосов
/ 04 июля 2019

Я пытаюсь создать оболочку роли, которая позволит мне ограничивать определенные страницы и контент для разных пользователей. У меня уже есть методы, реализованные для проверки этого, но оболочка / декоратор для реализации этого не работает, а иногда нет, и я понятия не имею, в чем причина.

Я искал вокруг в поисках убедительной причины того, что является причиной этой проблемы, но, к сожалению, обратные ссылки Flask не дают убедительной причины или решения, как большинство других поисков, которые я придумываю.

Я использую Flask-Login, Flask-Migrate и Flask-SQLAlchemy для управления моим веб-приложением, я изучил различные методы применения 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 голосов
/ 04 июля 2019

Итак, чтобы решить проблему, которая мучила меня последние пару часов, я посмотрел, как на самом деле работает модуль 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

0 голосов
/ 04 июля 2019

На первый взгляд это выглядит как конфликт с вашей run функцией в require_role декораторе ( документы ):

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