封装jwt_token,使用这两个函数之前,确保你有一个有效的
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中间件的定义,
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 提供的功能,可以在发送请求之前对其进行处理。这里的拦截器在每次发出请求之前,都会从
第二部分:
// 定义一个检查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();