You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pyJWT过期时间异常:已设置过期的Token仍可正常使用

JWT过期后仍可访问路由的问题修复

问题根源分析

  1. 签名密钥不匹配:登录生成Token时用的是app.config['SECRET_KEY'],但装饰器解码时硬编码为"testing",导致JWT的所有验证(包括过期时间)完全失效。
  2. 异常处理未中断请求:捕获Token过期/无效异常后仅打印日志,未返回错误响应,代码继续执行后续权限判断,可能引发未定义变量错误或错误放行。
  3. Token获取方式不一致:登录时将Token存入Cookie,但装饰器从Authorization头取Token,导致验证的Token与Cookie中存储的Token不一致。
  4. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:51:04