pyJWT过期时间异常:已设置过期的Token仍可正常使用
JWT过期后仍可访问路由的问题修复
问题根源分析
- 签名密钥不匹配:登录生成Token时用的是
app.config['SECRET_KEY'],但装饰器解码时硬编码为"testing",导致JWT的所有验证(包括过期时间)完全失效。 - 异常处理未中断请求:捕获Token过期/无效异常后仅打印日志,未返回错误响应,代码继续执行后续权限判断,可能引发未定义变量错误或错误放行。
- Token获取方式不一致:登录时将Token存入Cookie,但装饰器从
Authorization头取Token,导致验证的Token与Cookie中存储的Token不一致。 - Payload包含敏感信息:将用户密码存入JWT Payload,存在泄露风险(JWT Payload可被Base64直接解码)。
修复后的代码
教师装饰器代码
from functools import wraps from flask import request, jsonify import jwt def teachers(): def wrapper(f): @wraps(f) def decorator(*args, **kwargs): # 从Cookie读取Token(与登录存储方式统一) token = request.cookies.get("JWT") if not token: return jsonify({"message": "Token缺失"}), 401 try: # 使用与生成Token一致的密钥 data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"]) print("Token有效") except jwt.ExpiredSignatureError: return jsonify({"message": "Token已过期,请重新登录"}), 401 except jwt.InvalidTokenError: return jsonify({"message": "无效Token"}), 401 # 权限校验 if data['role'] == "teacher" or data['email'] == "admin@admin.com": return f(*args, **kwargs) else: return jsonify({"message": "权限不足"}), 403 return decorator return wrapper
登录接口代码
from datetime import datetime, timedelta from flask import request, jsonify, make_response import bcrypt import jwt @app.route('/teacherlogin', methods=['POST']) def teacherlogin(): email = request.form.get("email") password = request.form.get("password") role = request.form.get("role") # 参数校验 if not all([email, password, role]): return jsonify({"message": "缺少必填字段"}), 400 expire_time = datetime.now() + timedelta(seconds=120) try: user = users.find({"$and": [{"email": email}, {"role": role}]})[0] except IndexError: return jsonify({"message": "用户不存在"}), 404 # 密码校验(用checkpw更简洁) if bcrypt.checkpw(password.encode('utf8'), user["password"]): # 移除Payload中的敏感信息(密码) token = jwt.encode( { 'email': email, 'role': role, 'exp': expire_time }, app.config['SECRET_KEY'], algorithm="HS256" ) res = make_response(jsonify({"message": "登录成功"}), 200) res.set_cookie( "JWT", value=token, expires=expire_time, httponly=True, secure=True, # 生产环境开启,仅HTTPS传输 samesite="Lax" # 防CSRF攻击 ) return res else: return jsonify({"message": "密码错误"}), 401
额外优化建议
- 密钥安全:生产环境不要硬编码
SECRET_KEY,通过环境变量加载随机安全字符串。 - HTTPS强制:线上服务必须启用HTTPS,防止Token和Cookie被窃听。
- Cookie增强:保持
httponly=True防止XSS窃取Token,samesite根据业务需求选择Lax或Strict。
内容的提问来源于stack exchange,提问作者Quiblord
相关产品推荐
相关产品推荐

