封装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();