我正在尝试使another StackOverflow answer适应于有条件地应用装饰器以仅要求登录特定环境(最终是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:
,然后显示身份验证。
是的,我已经在shell中完成了export ENV=development
,并通过env
命令进行了确认。但是即使那样,它仍无法像我期望的那样读取环境变量。
也许这仅仅是错误的方法吗?我的最终目标是要求在一个特定环境上进行身份验证。我走的路有可能吗?可能吗?
答案 0 :(得分: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']
答案 1 :(得分:1)
让我从Flask的文档中粘贴一些东西
上下文的生命周期 将根据需要创建和销毁应用程序上下文。当Flask应用程序开始处理请求时,它将推送应用程序上下文和请求上下文。当请求结束时,它会弹出请求上下文,然后弹出应用程序上下文。通常,应用程序上下文将与请求具有相同的生存期。
现在让我们考虑装饰器的工作方式。它只是语法糖see this answer。
因此,在加载模块时将调用login_required装饰器,并且由于当前应用未处理请求而无法使用。
我会这样做,将条件移动到装饰器函数(与您的示例有关)。在处理请求时将调用它,因此您应该可以访问current_app。