根本原因是Flask-JWT-Extended默认仅从Authorization头严格解析“Bearer ”格式,多空格、少单词或误用“JWT”前缀均导致“Missing JWT”错误;同时identity未传唯一标识值、未配置黑名单机制或token存储位置错误也会引发关联问题。

为什么直接用 jwt_required() 会报错“Missing JWT”?
常见现象是:接口返回 401 Unauthorized,响应体里写着 Missing JWT,但你确实在请求头里加了 Authorization: Bearer xxx。根本原因通常是 Flask-JWT-Extended 默认只从 Authorization 头读 token,且严格要求格式为 Bearer —— 多一个空格、少一个单词、或者用了 JWT 前缀(如 JWT xxx)都会失败。
实操建议:
- 检查请求头是否拼写准确:
curl -H "Authorization: Bearer eyJ..." http://localhost:5000/protected - 确认没在前端 JS 里误写成
headers: { Authorization: 'JWT ' + token }—— 必须是Bearer - 如果必须兼容旧客户端(比如用
JWT前缀),需手动配置:app.config['JWT_HEADER_TYPE'] = 'JWT' - 调试时可在视图函数开头加
print(request.headers.get('Authorization'))确认实际收到的值
如何让 get_jwt_identity() 正确返回用户 ID 而不是 None?
这个函数返回 None 通常不是因为 token 无效,而是因为创建 token 时没按约定传入可识别的 identity。Flask-JWT-Extended 要求你在调用 create_access_token() 时,第一个参数必须是能唯一标识用户的值(如数据库 ID、用户名),而不是字典或对象。
实操建议:
- 错误写法:
create_access_token(identity={'id': 123, 'username': 'alice'})→get_jwt_identity()返回整个字典,但多数场景你只想要123 - 推荐写法:
create_access_token(identity=user.id),然后在受保护路由中直接用:current_user_id = get_jwt_identity() - 如果确实需要附带额外字段(如角色、权限),改用
create_access_token(identity=user.id, additional_claims={'role': 'admin'}),再通过get_jwt()获取 claims - 注意:identity 值会被序列化进 token payload,避免传敏感数据或大对象
为什么刷新 token 后原 access token 还能用?
Flask-JWT-Extended 默认不自动作废旧 token,它只校验签名和过期时间。这意味着只要 access token 没过期,即使用户已刷新,旧 token 依然有效 —— 这是设计使然,不是 bug。
实操建议:
- 若需强制单设备登录或即时失效,得自己实现黑名单机制(例如 Redis 存已注销的 jti)
- 启用 jti(JWT ID):配置
app.config['JWT_BLACKLIST_ENABLED'] = True和app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh'] - 在登出或刷新时,手动把旧 token 的 jti 加入黑名单:
from flask_jwt_extended import get_jti; jti = get_jti(encoded_token); redis.setex(f"blacklist:{jti}", expires_in, 'true') - 同时注册检查回调:
@jwt.token_in_blocklist_loader函数里查 Redis 是否存在该 jti - 注意:这会引入外部依赖和网络延迟,高频接口慎用
如何在非 Flask-RESTful 场景下获取当前用户信息?
很多项目用普通 @app.route 而非 MethodView,但照样能用 JWT。关键在于:只要路由被 @jwt_required() 装饰,get_jwt_identity() 和 get_jwt() 就可用,与视图类无关。
实操建议:
- 最简示例:
@app.route('/profile')
@jwt_required()
def profile():
user_id = get_jwt_identity()
claims = get_jwt() # 包含 exp, iat, jti, 以及 additional_claims
return {'user_id': user_id, 'role': claims.get('role')}
- 不要在未装饰的路由里调用这些函数,会抛
NoAuthorizationError - 如果想在模板中显示用户信息,可在
before_request里尝试获取并存入g,但要注意捕获异常(token 可能不存在或无效) - 别混淆
get_current_user()—— 这个函数并不存在,官方只提供get_jwt_identity()和get_jwt()
真正容易被忽略的是 token 的存储安全:前端不该把 access token 存 localStorage(易被 XSS 窃取),而应优先用 httpOnly Cookie;但 Flask-JWT-Extended 默认不支持 Cookie 方式传 token,需显式配置 JWT_TOKEN_LOCATION = ['cookies'] 并设置 JWT_COOKIE_SECURE 等参数 —— 这部分一旦配错,本地开发可能正常,上线后却完全无法认证。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











