【问题标题】:How to apply decorator to all blueprint urls in flask如何将装饰器应用于烧瓶中的所有蓝图 url
【发布时间】: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 应用装饰器?

【问题讨论】:

    标签: python flask flask-login


    【解决方案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 函数装饰了将响应对象作为输入的函数,但有人可能希望在路由返回值被响应之前对其进行预处理。
    猜你喜欢
    • 2020-09-06
    • 2012-07-14
    • 2021-04-06
    • 2013-08-21
    • 2016-02-21
    • 1970-01-01
    • 2012-06-16
    • 2020-11-30
    • 2019-11-13
    相关资源
    最近更新 更多