如何将装饰器应用于烧瓶中的所有蓝图 url

Posted

技术标签:

【中文标题】如何将装饰器应用于烧瓶中的所有蓝图 url【英文标题】:How to apply decorator to all blueprint urls in flask 【发布时间】:2016-09-16 07:49:22 【问题描述】:

我有一个蓝图和一些url函数,

admin_bp = Blueprint('admin', __name__)

@admin_bp.route('/dashboard', methods=['GET', ])
@flask_login.login_required
def dashboard():

    context = 

    page = 'admin/dashboard.html'
    return render_template(page, **context)

@admin_bp.route('/deny', methods=['GET', ])
@flask_login.login_required
def deny():
    return 'hey bro you dont belong here'

我不想为这个蓝图下的所有 url 函数复制粘贴 @flask_login.login_required 装饰器。有没有更好的方法可以为所有蓝图 url 应用装饰器?

【问题讨论】:

【参考方案1】:

您可以将before_request() 添加为将在视图中的每个请求之前运行的函数。

然后您需要添加装饰器以向before_request 函数注入额外的功能。您将需要导入 login_required 装饰器以确保每个端点都需要登录用户。这个装饰器是flask_login 库的一部分。

由于您的视图看起来像是管理员的一部分,因此我还建议您在 before_request 函数中添加一个自定义装饰器,例如 @role_required('admin')。该装饰器的功能将存在于其他地方并被导入。

@admin_bp.before_request
@login_required
def before_request():
    """ Protect all of the admin endpoints. """
    pass 

【讨论】:

嗨,我使用的是 jwt_required,而不是添加 login_required,但我认为它是相同的主体。但是,即使 @jwt_required 没有被填满,我仍然会进入函数 before_request 的主体。这是为什么呢?【参考方案2】:

子类Blueprint 并覆盖route 方法。

import flask

class MyBlueprint(flask.Blueprint):
  def route(self, rule, **options):
    def decorator(f):
      # these lines are copied from flask.Blueprint.route
      endpoint = options.pop("endpoint", f.__name__)
      self.add_url_rule(rule, endpoint, f, **options)

      # At this point flask.Blueprint.route simply returns f.
      # But you can nest a decorator.
      def inner(*args, **kwargs):
        # stuff you want to do before each request goes here
        try:
          result = f(*args, **kwargs)
          # stuff you want to do on successful responses (probing status, headers, etc.) goes here
        except Exception as e:
          # stuff you want to do on error responses goes here
          raise
      return inner

现在在您的蓝图中使用新的子类:

-v1_blueprint = Blueprint('v1', __name__)
+v1_blueprint = MyBlueprint('v1', __name__)

无需对个别路线进行更改。

这种方法的缺点是它从 Flask 内部复制代码。如果 flask.Blueprint.route 的实现在未来的版本中发生变化,您需要在升级 Flask 时同步 MyBlueprint。

【讨论】:

我无法为 flask_restx 的 Namespace 构建类似的东西 :(【参考方案3】:

先检查用户怎么样:

from flask.ext.login import current_user


@admin_bp.before_request
def check_user():
    if not current_user.is_authenticated():
        abort(401)

# your other functions without `@flask_login.login_required`

【讨论】:

这不能回答一般性问题,其中可能包括旨在执行请求之后的代码,而不仅仅是在它之前。 @after_request 函数装饰了将响应对象作为输入的函数,但有人可能希望在路由返回值被响应之前对其进行预处理。

以上是关于如何将装饰器应用于烧瓶中的所有蓝图 url的主要内容,如果未能解决你的问题,请参考以下文章

Flask视图:视图函数,类视图,蓝图使用方法整理

将装饰器应用于python包中的所有函数

如何将装饰器应用于每个 Flask 视图

python-flask复习—— 装饰器的坑及解决办法flask中的路由/实例化配置/对象配置/蓝图/特殊装饰器(中间件重定义错误页面)

如何将装饰器应用于 Cython cpdef 函数

Flask--路由, 配置, 蓝图