Flask蓝图中auth_required装饰器为何加括号才正常运行
报错原因解析
auth_required本身是装饰器工厂,不是可以直接挂在视图上的原生装饰器,这是问题的核心。
Flask注册路由时默认取被装饰函数的__name__属性作为端点名,同一个蓝图下不允许重名端点,你遇到的重名报错就来自这个机制。
两种写法的执行逻辑差异
先看auth_required的简化实现:
from functools import wraps def auth_required(arg=None, **config_kwargs): # 外层是工厂,接收鉴权配置参数,返回真正的装饰器 def _decorate(view_func): @wraps(view_func) # 把原视图的元信息(函数名等)复制到包装函数上 def wrapper(*args, **view_kwargs): # 实际鉴权逻辑:未登录就返回401 if not current_user.is_authenticated: abort(401) return view_func(*args, **view_kwargs) return wrapper # 兼容不带括号直接写@auth_required的场景 if callable(arg): return _decorate(arg) return _decorate
两种写法的区别就在这里:
- 写
@auth_required()(带括号)时,会先执行auth_required()拿到返回的_decorate,再用这个真正的装饰器包装视图。因为@wraps的作用,返回的包装函数会继承原视图的函数名:包装home时函数名是home,包装get_projects时函数名是get_projects,最终两个路由的端点名是core_bp.home和core_bp.get_projects,完全不冲突,程序正常运行。 - 写
@auth_required(不带括号)时,相当于直接执行home = auth_required(home),视图函数被当成arg参数传入。虽然兼容分支会直接返回包装结果,但你用的Flask-Security-Too版本在这个兼容分支里没有正确给返回的wrapper附加原视图的元信息,两次包装返回的函数名字都固定是wrapper。第一个路由注册时会创建core_bp.wrapper端点,第二个路由注册时发现同名端点已经存在,就抛出了端点覆盖的断言错误。
正确写法
Flask-Security-Too提供的所有鉴权类装饰器(auth_required、roles_required、permissions_required等),哪怕不需要传任何配置参数,都要带括号调用,示例代码如下:
@core_bp.route("/") @auth_required() def home(): print("test") return render_template('/core_bp/index.html') @core_bp.route("/get-projects") @auth_required() def get_projects(): searchTerm = request.args.get("search") data = [ "buchsweg 5" , "tannenweg 1" ] return jsonify(data)
内容的提问来源于stack exchange,提问作者rapsli
相关产品推荐
相关产品推荐

