flask-HTTPTokenAuth Token验证失败:使用MultiAuth仍触发密码输入提示
Flask-HTTPAuth Token认证时弹出密码输入框问题
我正在学习Miguel Grinberg的《Flask Web Development》第14章的API认证流程,尝试把示例代码适配到最新版flask-HTTPAuth。目前邮箱+密码的HTTPBasicAuth认证能正常通过,但用Token认证时,系统还是会弹出密码输入提示。
我的app/api/authentication.py代码如下:
from flask import g, jsonify from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth, MultiAuth from ..models import User from . import api from .errors import forbidden, unauthorized basic_auth = HTTPBasicAuth() token_auth = HTTPTokenAuth(scheme='Bearer') multi_auth = MultiAuth(basic_auth, token_auth) @basic_auth.verify_password def verify_password(email, password): if email == '': return False user = User.query.filter_by(email=email).first() if not user: return False g.current_user = user g.token_used = False if user.verify_password(password): return user else: return False @token_auth.verify_token def verify_token(token): user = User.verify_auth_token(token) if user: g.current_user = user g.token_used = True return user else: return False @basic_auth.error_handler def auth_error(): return unauthorized('Invalid credentials') @token_auth.error_handler def auth_error(): return unauthorized('Invalid credentials') @api.before_request @multi_auth.login_required def before_request(): if not g.current_user.is_anonymous and not g.current_user.confirmed: return forbidden('Unconfirmed account') @api.route('/tokens/', methods=['POST']) @multi_auth.login_required def get_token(): if g.current_user.is_anonymous or g.token_used: return unauthorized('Invalid credentials') return jsonify({'token': g.current_user.generate_auth_token(), 'expiration': 3600})
使用环境:
- Python 3.10.6
- Flask 2.2.2
- HTTPie 3.2.1
请问问题出在哪里?
问题排查与解决
1. 调整MultiAuth认证顺序
MultiAuth会按传入的认证方式顺序依次尝试验证。你当前先传入basic_auth再传token_auth,导致Token认证失败(哪怕请求携带Token)时,会自动降级到BasicAuth,触发密码输入提示。
修改MultiAuth初始化顺序,将Token认证放在前面:
multi_auth = MultiAuth(token_auth, basic_auth)
2. 规范认证验证函数的返回值
最新版flask-HTTPAuth要求验证函数返回布尔值表示认证是否通过,而非用户对象。虽然当前代码中返回用户对象在布尔判断上能生效,但为了兼容新版规范,建议明确返回布尔值:
修改verify_token函数:
@token_auth.verify_token def verify_token(token): user = User.verify_auth_token(token) if user: g.current_user = user g.token_used = True return True # 明确返回布尔值 else: return False
修改verify_password函数:
@basic_auth.verify_password def verify_password(email, password): if email == '': return False user = User.query.filter_by(email=email).first() if not user: return False g.current_user = user g.token_used = False return user.verify_password(password) # 直接返回密码验证的布尔结果
3. 修正错误处理器的命名冲突
你为basic_auth和token_auth定义了同名的auth_error函数,可能导致后定义的处理器覆盖前一个。建议给两个处理器起不同名称:
@basic_auth.error_handler def basic_auth_error(): return unauthorized('Invalid credentials') @token_auth.error_handler def token_auth_error(): return unauthorized('Invalid credentials')
4. 确认HTTPie请求格式
确保发送Token请求时使用正确的Bearer格式,避免因请求格式错误导致Token认证失败:
http GET http://localhost:5000/api/your-target-endpoint Authorization:"Bearer <你的Token值>"
完成以上调整后,Token认证会被优先处理,验证通过则不会触发BasicAuth的密码提示。
内容的提问来源于stack exchange,提问作者Darwin von Corax
相关产品推荐
相关产品推荐

