如何将装饰器应用于烧瓶中的所有蓝图 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的主要内容,如果未能解决你的问题,请参考以下文章
python-flask复习—— 装饰器的坑及解决办法flask中的路由/实例化配置/对象配置/蓝图/特殊装饰器(中间件重定义错误页面)