我有一个蓝图和一些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
装饰器。有没有更好的方法可以为所有蓝图网址应用装饰器?
您可以添加
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
子类
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 与其同步。
先检查一下用户如何:
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`
添加在@kartik 答案之上
我尝试做同样的事情,特别是我需要一个装饰功能(与@Robert不同)答案,它使用
before_request
提供了一个解决方案,它是一个中间件,并且不包装函数本身,因为我的问题需要装饰来分析代码.
我解决了这个问题,没有从 Flask 的
Scaffold
类中复制代码。my_decorator
可以是任何你需要的装饰器。
import typing as t
from functools import wraps
from flask import Flask
def my_decorator(f):
@wraps(f)
def inner(*args, **kwargs):
print(f"Entering {f.__name__}")
result = f(*args, **kwargs)
print(f"Finished {f.__name__}")
return result
return inner
class MyFlask(Flask):
def route(self, rule: str, **options: t.Any) -> t.Callable:
route_decorator = super().route(rule, **options)
def inner(f):
new_f = my_decorator(f)
return route_decorator(new_f)
return inner
app = MyFlask("app")
@app.route("/test")
def test():
print("In test")
return {}
app.run()
然后,运行:
import requests
requests.get("http://localhost:5000/test")
打印
Entering test
In test
Finished test