直接用PyJWT因其轻量、可控性强,能直面密钥管理、exp/nbf校验、算法选择等核心约束;而Flask-JWT已停更,Flask-JWT-Extended则默认行为过多易掩盖逻辑细节。

为什么直接用 PyJWT 而不是 Flask-JWT 或 Flask-JWT-Extended?
Flask-JWT 已停止维护,Flask-JWT-Extended 功能强但引入大量默认行为(比如自动处理 Authorization header、强制使用 get_jwt_identity()),容易掩盖认证逻辑细节。实际项目中,你更需要明确控制 token 签发、校验、刷新和失效逻辑——尤其是当要对接前端 cookie + httpOnly、或支持多签发方、或自定义 claim 结构时。
PyJWT 更轻量,API 清晰,且能让你直面 JWT 的核心约束:签名密钥管理、过期时间校验、算法选择、时钟偏移容忍等。
- 必须用
HS256或RS256,别用none算法(存在漏洞) -
exp和nbf字段需显式校验,PyJWT 默认不校验nbf - 密钥不能硬编码在代码里,应从环境变量读取:
os.getenv("SECRET_KEY")
如何生成带用户信息的 JWT 并安全返回?
签发 token 时,只放最小必要字段(如 user_id、role),避免泄露敏感信息;同时设置短有效期(如 15 分钟),配合 refresh token 机制。
import jwt
import datetime
import os
<p>def create_access_token(user_id: int, role: str = "user") -> str:
payload = {
"user_id": user_id,
"role": role,
"exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=15),
"iat": datetime.datetime.utcnow(),
"jti": str(uuid.uuid4()), # 防重放,需存入 Redis 校验
}
return jwt.encode(payload, os.getenv("SECRET_KEY"), algorithm="HS256")
</p>
- 别把密码、邮箱、手机号放进 payload —— token 可被 base64 解码,无加密
-
exp必须设,否则 token 永不过期;iat建议加上,便于调试签发时间 - 若需防 token 重放,用
jti字段 + Redis 存储已用 jti(签发时写入,校验前查重)
如何在 Flask 路由中校验 JWT 并提取用户身份?
不要在每个视图函数里重复写解码逻辑。用 @app.before_request 或自定义装饰器统一拦截,把解析结果挂到 g 对象上,后续视图可直接访问 g.current_user_id。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
from flask import request, g, jsonify
from functools import wraps
<p>def require_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Bearer "):
return jsonify({"error": "Missing or invalid Authorization header"}), 401</p><pre class="brush:php;toolbar:false;"> token = auth_header[7:]
try:
payload = jwt.decode(
token,
os.getenv("SECRET_KEY"),
algorithms=["HS256"],
options={"require": ["exp", "iat"], "verify_exp": True},
)
g.current_user_id = payload["user_id"]
g.current_role = payload["role"]
except jwt.ExpiredSignatureError:
return jsonify({"error": "Token expired"}), 401
except jwt.InvalidTokenError:
return jsonify({"error": "Invalid token"}), 401
return f(*args, **kwargs)
return decorated使用示例
@app.route("/profile") @require_auth def profile(): return jsonify({"user_id": g.current_user_id, "role": g.current_role})
- 必须检查
Authorizationheader 格式,空值、格式错误都应拒掉 -
options={"verify_exp": True}显式开启过期校验(PyJWT 2.x+ 默认开启,但老版本需手动设) - 别用
try/except Exception,精确捕获jwt.ExpiredSignatureError和jwt.InvalidTokenError
cookie + httpOnly 方式传 token 时要注意什么?
前端用 fetch 发请求时,默认不带 cookie,需设 credentials: "include";后端则要用 set_cookie 设置 httpOnly=True、secure=True(HTTPS 环境)、samesite="Lax"。
@app.route("/login", methods=["POST"])
def login():
# ... 验证用户名密码
token = create_access_token(user.id)
response = jsonify({"msg": "logged in"})
response.set_cookie(
"access_token",
token,
httponly=True,
secure=True, # 生产必须开
samesite="Lax",
max_age=900, # 15 分钟,与 token exp 一致
)
return response
- cookie 名别叫
token或jwt,避免被通用扫描规则误报 -
max_age应 ≤ token 的exp时长,否则 cookie 过期后前端仍可能发旧 token - 若前端是跨域 SPA(如 React 在 localhost:3000),需同时配 Flask 的
CORS支持 credentials
最易被忽略的是时钟同步问题:服务器和客户端系统时间偏差超过 60 秒,exp/nbf 校验就会失败。生产环境务必用 NTP 同步时间,开发时可在 jwt.decode 中加 leeway=60 容忍 1 分钟偏差。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










