Как заменить декоратор во время выполнения? - PullRequest
0 голосов
/ 01 апреля 2019

Я пытаюсь адаптировать другой ответ StackOverflow об условном применении декоратора, требующего только входа в систему для определенной среды (в конечном итоге staging, но development, пока я не получу эту работу).С этой целью я начал со следующего

auth = HTTPDigestAuth()

def login_required(dec, condition):
    def decorator(func):
        if not condition:
            return func
        return dec(func)
    return decorator

@bp.route('/auth')
@login_required(auth.login_required, current_app.config['ENV'] != 'development')
def auth_route():
    return current_app.config['ENV']

Когда я запускаю сервер, я получаю ошибку RuntimeError: Working outside of application context.Попробовав несколько предложений из более ранней версии этого вопроса, я заставил RuntimeError исчезнуть, но декоратор все еще не применяется правильно, когда я хочу.Вот текущая версия:

def login_required(dec):
    def decorator(func):
        if not os.environ.get('ENV') != 'development':
            return func
        return dec(func)
    return decorator

@bp.route('/auth')
@login_required(auth.login_required)
def auth_route():
    return current_app.config['ENV']

Это никогда не возвращает функцию auth.login_reqired.Он всегда пропускает браузер без аутентификации.

Итак, я попытался изменить условие на

if not os.environ.get('ENV') is not None:

, и затем показывается аутентификация.

Да, у меня естьсделал export ENV=development в оболочке и подтвердил это командой env.Но даже тогда он не читает переменную окружения, как я ожидал.

Возможно, это просто неправильный путь?Моя конечная цель - потребовать аутентификацию в одной конкретной среде.Это возможно с пути, по которому я иду?Возможно ли это вообще?

Ответы [ 2 ]

1 голос
/ 01 апреля 2019

Позвольте мне вставить что-нибудь из документации Flask

Время жизни контекста Контекст приложения создается и уничтожается по мере необходимости. Когда приложение Flask начинает обрабатывать запрос, оно выдвигает контекст приложения и контекст запроса. Когда запрос заканчивается, он извлекает контекст запроса, затем контекст приложения. Как правило, контекст приложения будет иметь то же время жизни, что и запрос.

Теперь давайте рассмотрим, как работают декораторы. Это просто синтаксический сахар см. Этот ответ .

Таким образом, декоратор login_required вызывается, когда модуль загружен, а текущее приложение еще не доступно, поскольку оно не обрабатывает запрос.

Я бы сделал так, переместил условие в функцию декоратора (относится к вашему примеру). Он будет вызван во время обработки запроса, поэтому у вас должен быть доступ к current_app.

1 голос
/ 01 апреля 2019

current_app - это локальный контекстный прокси, который имеет значение только во время запроса.Это означает, что вы не можете использовать его до запроса, то есть как часть декоратора.

Использование current_app обычно является хорошей практикой, поскольку Flask позволяет настраивать несколько приложений.Однако в вашем конкретном случае это на самом деле не нужно.Например, следующее будет работать, потому что он использует объект приложения напрямую вместо current_app прокси:

from yourpackage import app

@bp.route('/auth')
@login_required(auth.login_required, app.config['ENV'] != 'development')
def auth():
    return current_app.config['ENV']
...