如何在带有参数的Flask中创建python decorator函数(用于授权)

如何在带有参数的Flask中创建python decorator函数(用于授权),python,flask,decorator,Python,Flask,Decorator,我在flask登录时使用了一个flask片段,用于检查用户是否登录: 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:

我在flask登录时使用了一个flask片段,用于检查用户是否登录:

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
我也想做一些类似的授权。现在,我有很多视图来检查用户是否拥有资源,比如
热狗
资源

如果登录用户是特定热狗的所有者,他可以编辑和管理他的热狗。如果他不是,我就把他踢到未经授权的屏幕上

@app.route('/<hotdog>/addmustard/',methods=["GET"])
@logged_in
def addmustard(hotdog):
    if not (authorizeowner(hotdog)):
        return redirect(url_for('unauthorized'))
    do_stuff()
从错误消息中,decorator似乎没有从路由中的变量接收Flask视图可以访问的热狗参数。我的希望是像

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
@app.route('/<hotdog>/addmustard/',methods=["GET"])
@logged_in
@owns_hotdog(hotdog)
def addmustard(hotdog):
    do_stuff()
@app.route('//add芥末/',方法=[“GET”])
@登录
@拥有热狗(hotdog)
def添加芥末(热狗):
做某事
所有东西都与我当前的authorizeowner(hotdog)函数配合使用,但将其作为路径顶部的包装,而不是路径中的第一行,似乎更干净

其他一些注意事项:

  • 我知道Flask Security和Flask Principal可以管理 授权给我。不幸的是,我使用的是不受支持的 数据库后端,我无法使用这些扩展。所以,我 被迫在没有它们的情况下进行身份验证
  • 如果你看到这样做有任何明显的漏洞,请让我知道
      以下是如何做到这一点:

      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接受参数时,它实际上不是一个decorator,而是一个返回真正decorator的工厂函数

      但如果我是你,我会使用Flask登录进行身份验证,并使用定制的装饰器和函数来增强它,就像你处理授权一样


      我仔细研究了一下,但发现它对我的口味来说太复杂了。尚未检查Flask安全性,但我相信它使用Flask主体进行授权。总的来说,我认为大多数情况下,使用一些自定义代码登录Flask就足够了。

      尝试将
      如果未授权所有者(热狗)
      替换为
      如果未授权所有者(*args,**kwargs)
      ,并从您的装饰器中删除
      (热狗)
      。感谢Audrius的代码和double关于Flask登录的建议。我不太明白更新包装与包装的区别。我会像以前一样在视图中称之为
      @app.route('//add芥末/',methods=[“GET”])@logged_in@owns\u hotdog(热狗)def add芥末(热狗):dou stuff()
      是的,您将使用
      @owns\u hotdog(热狗)
      作为装饰程序。我的示例还包括身份验证部分,因此您不需要
      @logged\u-in
      decorator,但如果要使用它,请从我的代码中删除
      if-logged\u-in()…
      部分。另外,
      logged\u in()
      函数在我的示例中与您的decorator不同,我只是使用这个名称来暗示它需要检查用户是否登录并选择相同的名称。抱歉,如果这造成了任何混乱。至于
      wrapps()
      update\u wrapper()
      ,这些函数不是必需的,但最好使用它们。当decorator返回一个不同于它作为参数得到的函数时,这些函数使返回的函数看起来像原始函数,即它们复制docstring和名称。如果想了解更多信息,请查看
      functools
      模块的文档。当我使用@owns\u hotdog(hotdog)运行此操作时,我收到一个错误,导致flask无法启动。视图文件显示
      @owns\u hotdog(hotdog)name错误:未定义名称“hotdog”
      出于某种原因,似乎不允许我将参数传递给工厂函数?修饰符在函数定义时执行,因此必须在那时定义名称
      hotdog
      。我得到的印象是,您正试图从您的路线访问
      零件的价值。如果是这种情况,请检查哪里可以找到一个演示如何执行此操作的示例。