我正在尝试调整另一个 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:
然后显示身份验证。
是的,我已经在 shell 中做了一个export ENV=development
并使用env
命令确认了它。但即便如此,它也没有像我期望的那样读取环境变量。
也许这只是错误的方法?我的最终目标是要求在一个特定环境中进行身份验证。我所走的路可能吗?可能吗?
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']
让我粘贴 Flask 文档中的内容
上下文的生存期 根据需要创建和销毁应用程序上下文。当 Flask 应用程序开始处理请求时,它会推送应用程序上下文和请求上下文。当请求结束时,它会弹出请求上下文,然后弹出应用程序上下文。通常,应用程序上下文的生存期与请求相同。
现在让我们考虑一下装饰器的工作原理。这只是一个句法糖看到这个答案。
因此,在加载模块时调用login_required装饰器,并且当前应用程序尚不可用,因为它未处理请求。
我会这样做,将条件移动到装饰器函数(与您的示例相关)。它将在处理请求时被调用,因此您应该有权访问current_app。