生成token以及白名单过滤

 封装jwt_token,使用这两个函数之前,确保你有一个有效的SECRET_KEY来对令牌进行签名和验证,它通常是一个随机生成的字符串,用来保证JWT的安全性。在生产环境中,不要将SECRET_KEY硬编码在代码中,它应该从环境变量或配置文件中安全地加载。

import jwt
from serve_video.settings.dev import SECRET_KEY


def generate_jwt(payload, expiry):
    _payload = {
        'exp': expiry
    }
    _payload.update(payload)
    token = jwt.encode(_payload, SECRET_KEY, algorithm='HS256')
    return token


def verify_jwt(token):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
    except jwt.exceptions.ExpiredSignatureError:
        # Token已过期
        payload = None
    except jwt.exceptions.InvalidSignatureError:
        # Token签名无效
        payload = None
    return payload

调用封装后的jwt_token通过将精确到微秒的时间加上过期的时间结合用户ID存储到载荷中

def generate_token(request, user):
    login(request, user)
    # 得到一个精确到微秒的当前UTC时间
    expiry = datetime.utcnow() + timedelta(days=3)
    token = generate_jwt({'user_id': user.id}, expiry)
    return token

白名单在Django中间件的定义,WhiteListMiddleware 继承自 MiddlewareMixin。该中间件使用名为 whitelist 的列表来确定哪些路径不应该受到JWT验证的限制。对于请求的路径不在这个白名单中的请求,该中间件会执行一系列的检查和操作。下面将添加注释来解释代码的工作原理:

class WhiteListMiddleware(MiddlewareMixin):
    # 定义白名单路径列表,这些路径不需要进行JWT验证
    whitelist = ['/user/logout/', '/user/baibu/', '/orders/commit/']

    def process_request(self, request):
        # 检查当前请求的路径是否在白名单中,如果在,直接允许通过不进行下面的验证
        if request.path_info not in self.whitelist:
            return

        try:
            # 获取与名称'jwt_token'相关联的Redis连接
            redis_conn = get_redis_connection('jwt_token')
            # 从请求头中读取'Authorization'字段,这是JWT token
            token = request.META.get('HTTP_AUTHORIZATION')

            # 如果Token不存在,返回402响应码和错误信息
            if not token:
                return JsonResponse({"code": 402, 'errmsg': 'Token未提供'})

            # 检查该Token是否在Redis的'logged_out_users'集合的分数中,以确认用户是否已登出
            if redis_conn.zscore('logged_out_users', token):
                return JsonResponse({"code": 406, 'errmsg': '已经退出,不能进行操作'})
            
            # 验证JWT Token的有效性
            payload = verify_jwt(token)

            # 如果payload为空,表示Token无效,返回403响应码和错误信息
            if not payload:
                return JsonResponse({"code": 403, 'errmsg': '无效的Token'})

            # 获取Token的过期时间戳
            exp = payload.get('exp')
            # 获取当前的时间戳
            now = int(time.time())

            # 如果Token已经过期,返回404响应码和错误信息
            if exp is not None and int(exp) < now:
                return JsonResponse({"code": 404, 'errmsg': 'Token已过期'})
            
            # 获取Token中的用户ID
            uid = payload.get('user_id')
            # 将uid保存在request对象中,以便其他地方能够访问
            request.uid = uid
            
            # 正常情况,不返回任何东西表示请求可以继续通过到视图函数
            return None

        except KeyError:
            # KeyError异常,返回405响应码和错误信息
            return JsonResponse({"code": 405, 'errmsg': '关键字错误'})
        except Exception as e:
            # 记录其他类型的异常
            logger.error(e)
            # 返回401响应码和未知错误信息
            return JsonResponse({"code": 401, 'errmsg': '未知错误'})

Axios 拦截器配置和一个检查Token过期的定时器函数。

第一部分:

// Axios 请求拦截器
axios.interceptors.request.use(config => {
  // 尝试从localStorage中获取名为"token"的数据项
  let token = localStorage.getItem("token")
  
  // 如果token存在,则将其添加到即将发送的请求的头部
  // 这样每个请求都会附带Authorization头,携带JWT token
  if (token) {
      config.headers['Authorization'] = token
  }
  
  // 返回配置对象,以便请求可以使用这些配置
  return config;
})

拦截器是 Axios 提供的功能,可以在发送请求之前对其进行处理。这里的拦截器在每次发出请求之前,都会从 localStorage 中获取名称为 “token” 的数据项(如果存在)。如果存在token,则会把这个token添加到请求的头部中的 Authorization 字段里,这种方式通常用于将用户认证信息发送到服务器。

第二部分:

// 定义一个检查Token过期的函数
const checkTokenExpiration = () => {
  // 获取当前时间的时间戳
  const currentTime = new Date().getTime();
  // 尝试从localStorage中获取名为"expireTime"的数据项
  const storedExpireTime = localStorage.getItem('expireTime');

  // 检查当前时间是否已经超过存储的过期时间戳
  if (currentTime > storedExpireTime) {
    // 如果超过了,清除localStorage中的token, user_id和expireTime
    localStorage.removeItem('token');
    localStorage.removeItem('user_id');
    localStorage.removeItem('expireTime');
  } else {
    // 如果没有过期,设置一个定时器,在token过期时刻触发此函数
    setTimeout(checkTokenExpiration, storedExpireTime - currentTime);
  }
};

// 调用函数以启动定时器,以便检查和管理Token的有效性
checkTokenExpiration();

 // 定义一个检查Token过期的函数 const checkTokenExpiration = () => { // 获取当前时间的时间戳 const currentTime = new Date().getTime(); // 尝试从localStorage中获取名为"expireTime"的数据项 const storedExpireTime = localStorage.getItem('expireTime'); // 检查当前时间是否已经超过存储的过期时间戳 if (currentTime > storedExpireTime) { // 如果超过了,清除localStorage中的token, user_id和expireTime localStorage.removeItem('token'); localStorage.removeItem('user_id'); localStorage.removeItem('expireTime'); } else { // 如果没有过期,设置一个定时器,在token过期时刻触发此函数 setTimeout(checkTokenExpiration, storedExpireTime - currentTime); } }; // 调用函数以启动定时器,以便检查和管理Token的有效性 checkTokenExpiration();