Flask添加基于角色的访问装饰器时出现NameError问题求助
问题分析与修复方案
问题根源
- 装饰器执行顺序错误:Python装饰器是从下往上应用的,你写的
@token_required在@admin_required上方,实际会先执行admin_required的权限检查,再执行token_required的用户认证。但权限检查需要current_user,此时current_user还未被认证生成,自然找不到。 - 参数传递问题:
token_required会把current_user作为参数传给后续函数,但permission_required的装饰器函数没有接收这个参数,直接引用current_user变量,导致作用域错误。
修复方案
方案一:调整装饰器顺序+修改权限装饰器接收参数
- 调换装饰器顺序:让
token_required先执行(放在下方),确保用户认证完成后再做权限检查:
@auth.route('/testing', methods=['GET']) @admin_required @token_required # 先执行token_required注入current_user,再执行admin_required检查权限 def testing(current_user): print(current_user.can(Permission.ADMIN)) return "successful"
- 修改
permission_required装饰器:让它接收current_user参数,确保能拿到用户对象:
def permission_required(permission): def decorator(f): @wraps(f) def decorated_function(current_user, *args, **kwargs): if not current_user.can(permission): return jsonify({'message' : 'You dont have right permission!'}), 401 return f(current_user, *args, **kwargs) return decorated_function return decorator
方案二:使用Flask全局请求对象存储用户(更优雅)
如果你的项目基于Flask,推荐用全局g对象存储current_user,避免参数传递的麻烦:
- 修改
token_required:将查询到的用户存入Flask全局g对象:
from flask import g def token_required(f): @wraps(f) def decorated(*args, **kwargs): token = None if 'x-access-token' in request.headers: token = request.headers['x-access-token'] if not token: return jsonify({'message' : 'Token is missing !!'}), 401 try: data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"]) current_user = db_session.query(Account).filter_by(public_id=data['public_id']).first() g.current_user = current_user # 存入全局对象 except: return jsonify({ 'message' : 'Token is invalid !!' }), 401 return f(*args, **kwargs) return decorated
- 修改
permission_required:从全局g对象中获取用户:
from flask import g def permission_required(permission): def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): current_user = g.current_user if not current_user.can(permission): return jsonify({'message' : 'You dont have right permission!'}), 401 return f(*args, **kwargs) return decorated_function return decorator
- 简化测试函数:不需要再接收
current_user参数:
@auth.route('/testing', methods=['GET']) @token_required @admin_required def testing(): print(g.current_user.can(Permission.ADMIN)) return "successful"
内容的提问来源于stack exchange,提问作者ussrback
相关产品推荐
相关产品推荐

