【发布时间】:2019-04-17 06:15:24
【问题描述】:
由于@route 装饰器必须使用给予装饰器的当前回调来注册视图,它has to be the outermost decorator 在处理请求时接收要调用的正确函数。
这可能会导致视图已被装饰,但由于装饰器的顺序错误,因此不会调用被装饰的函数。如果用于装饰需要用户登录,具有特定角色或具有特定标志的视图,则该检查将被静默省略。
我们当前的解决方法是让标准操作是拒绝访问资源,然后要求装饰器允许访问。在这种情况下,如果在处理请求时没有调用装饰器,则请求将失败。
但是在某些用例中这会变得很麻烦,因为它需要您装饰所有视图,除了少数应该被豁免的视图。对于纯粹的分层布局,这可能有效,但对于检查单个标志,结构可能会变得复杂。
是否有适当的方法来检测我们在装饰层次结构中的有用位置被调用? IE。我们能否检测到尚未将route 装饰器应用于我们要包装的函数?
# wrapped in wrong order - @require_administrator should be after @app.route
@require_administrator
@app.route('/users', methods=['GET'])
实现为:
def require_administrator(func):
@functools.wraps(func)
def has_administrator(*args, **kwargs):
if not getattr(g, 'user') or not g.user.is_administrator:
abort(403)
return func(*args, **kwargs)
return has_administrator
在这里我想检测我的自定义装饰器是否在@app.route 之后被包装,因此在处理请求时永远不会被调用。
使用functools.wraps在所有方面都将被包装的函数替换为新的,所以查看要被包装的函数的__name__会失败。这也发生在装饰器包装过程的每一步。
我尝试查看traceback 和inspect,但没有找到任何合适的方法来确定序列是否正确。
更新
我目前最好的解决方案是根据已注册的端点集检查调用的函数名称。但是由于 Route() 装饰器可以更改端点的名称,因此在这种情况下,我也必须为我的装饰器支持它,并且如果不同的函数使用与当前相同的端点名称,它将静默通过函数。
它还必须迭代注册的端点集,因为我无法找到一种简单的方法来检查端点名称是否存在(通过尝试使用它构建 URL 并捕获异常可能更有效)。
def require_administrator_checked(func):
for rule in app.url_map.iter_rules():
if func.__name__ == rule.endpoint:
raise DecoratorOrderError(f"Wrapped endpoint '{rule.endpoint}' has already been registered - wrong order of decorators?")
# as above ..
【问题讨论】:
标签: python flask python-decorators