我在烧瓶登录时使用了烧瓶片段来检查用户是否已登录:
from functools import wraps
def logged_in(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if session.get('logged_in') is not None:
return f(*args, **kwargs)
else:
flash('Please log in first.', 'error')
return redirect(url_for('login'))
return decorated_function
我装饰了这样的观点:
@app.route('/secrets', methods=['GET', 'POST'])
@logged_in
def secrets():
error = None
我也想为授权做类似的事情。现在,我有很多观点来检查用户是否拥有资源,让我们说hotdogs
资源。
如果logged_in用户是该特定热狗的所有者,他可以编辑和管理他的热狗。如果他不是,我会把他踢到未经授权的屏幕上。
@app.route('/<hotdog>/addmustard/',methods=["GET"])
@logged_in
def addmustard(hotdog):
if not (authorizeowner(hotdog)):
return redirect(url_for('unauthorized'))
do_stuff()
authorizeowner()
将热狗作为输入,并检查记录的热狗所有者是否与会话变量中列出的所有者名称匹配。
我尝试制作一个类似于我登录的owns_hotdog包装器/装饰器功能,但它抱怨它不接受参数。我怎样才能达到类似的效果?有点像...
def owns_hotdog(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not authorizeowner(hotdog):
return f(*args, **kwargs)
else:
flash('Please log in first.', 'error')
return redirect(url_for('login'))
return decorated_function
从错误消息中,装饰器似乎没有收到Flask视图可以从路径中的变量访问的热狗参数。我的希望是... ...
@app.route('/<hotdog>/addmustard/',methods=["GET"])
@logged_in
@owns_hotdog(hotdog)
def addmustard(hotdog):
do_stuff()
一切都适用于我当前的authorizeowner(热狗)功能,但是将它作为路由顶部的包装器而不是作为路径中的第一行,这似乎更清晰。
其他一些说明:
答案 0 :(得分:20)
以下是如何操作:
from functools import update_wrapper
def owns_hotdog(hotdog):
def decorator(fn):
def wrapped_function(*args, **kwargs):
# First check if user is authenticated.
if not logged_in():
return redirect(url_for('login'))
# For authorization error it is better to return status code 403
# and handle it in errorhandler separately, because the user could
# be already authenticated, but lack the privileges.
if not authorizeowner(hotdog):
abort(403)
return fn(*args, **kwargs)
return update_wrapper(wrapped_function, fn)
return decorator
@app.errorhandler(403)
def forbidden_403(exception):
return 'No hotdogs for you!', 403
当decorator接受参数时,它不是真正的装饰器,而是 factory 函数,它返回真正的装饰器。
但如果我是你,我会使用Flask-Login进行身份验证,并使用自己的定制装饰器和函数来扩充它以处理授权。
我看了Flask-Principal,但发现它的味道过于复杂。没有检查Flask-Security,但我相信它使用Flask-Principal进行授权。总的来说,我认为使用一些自定义代码的Flask-Login在大多数情况下都足够了。