0

我正在尝试调整另一个 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在 shell 中做了一个并用env命令确认它。但即便如此,它也没有像我预期的那样读取环境变量。

也许这只是错误的做法?我的最终目标是要求在一个特定环境中进行身份验证。这可能与我正在走的路吗?有可能吗?

4

2 回答 2

1

current_app是一个上下文本地代理,仅在请求期间才有意义。这意味着您不能在请求之前使用它,即作为装饰器的一部分。

使用current_app通常是好的做法,因为 Flask 允许配置多个应用程序。但是,在您的特定情况下,实际上没有必要。例如,以下内容会起作用,因为它直接使用 app 对象而不是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']
于 2019-03-31T22:50:10.883 回答
1

让我从 Flask 的文档中粘贴一些东西

上下文的生命周期 应用程序上下文根据需要创建和销毁。当 Flask 应用程序开始处理请求时,它会推送应用程序上下文和请求上下文。当请求结束时,它会弹出请求上下文,然后是应用程序上下文。通常,应用程序上下文与请求具有相同的生命周期。

现在让我们考虑装饰器是如何工作的。这只是一个语法糖看到这个答案

所以 login_required 装饰器在模块加载时被调用,当前应用程序还不可用,因为它没有处理请求。

我会这样做,将条件移动到装饰器函数(与您的示例相关)。它将在处理请求时被调用,因此您应该可以访问 current_app。

于 2019-03-31T22:58:31.020 回答