思路
- 当用户进入和刷新页面时,把当前的token放入黑名单(维护在redis中,其中把创建token的时间戳作为key,截止时间作为value),并且创建一个新的token传回前端
- 判断黑名单中的token是否过期:
利用定时任务:
node-schedule
;每隔一短时间(一天)判断一下redis黑名单中的token是否过期,如果过期把他从黑名单删除 - 当验证验证token时再增加一个对黑名单的判断:
获取当前的token信息(子req.user中)获取创建时间戳,判断是黑名单中是否含有,如果含有则调用express-jwt的
isRevoked
的相关处理
router.post('/init/', function(req, res, next) {
console.log(req.user)//打印:
}
打印: 其中iat为token创建时间,exp是截止时间或者说失效时间

redis的增删改查,实现黑名单的遍历与删除
- 使用
hget/hset
读写数据
其中Redis 中 set 与 hset 区别: set/get方法存储的是单个数据,相当于往学校里面塞入一个学生,查找的时候全部集合到一起,点名找出来。 hset/hget 存储的是一个数据对象,相当于在学校塞入学生的时候,确定好了班级,查找的时候,先找到班级再找学生。
-
hkeys
获取散列包含的所有键、hvals
获取散列包含的所有值,可用于遍历查找 -
del
,删除
//判断redis黑名单中是否有token超时
redisClient.hvals("token", function(err, tokenValue) { //tokenValue是一个数组,值是value
tokenValue.forEach(function(value, i) {
if(date>value){
//超时,删除
console.log('超时,删除')
redisClient.del('token', value, function(err, resData) {
if(err){
console.log('delErr:',err)
}
console.log('删除成功!')
})
}else{
console.log('未超时')
}
});
})
把上面的代码放入node-schedule
,使其每隔一段时间执行一次
express-jwt的isRevoked配置项,作废token
isRevoked配置项接收一个函数,如果返回done(null, true)
表示token被吊销,报错403;返回done(null, false)
则表示token正常
let isRevokedCallback = function(req, payload, done) {
//payload当前的token信息----如;{ username: 'test', iat: 1591179448, exp: 1591784248 }
//是否含有
redisClient.hexists('token', payload.time, function(err, tokenNumber) {
if(err){
console.log('hashErr:',err)
}
if(tokenNumber == 1){
console.log('在黑名单中')
return done(null, true) // 第二个参数为 true 则不通过
}else{
console.log('不在黑名单中')
return done(null, false) //通过
}
})
}
const jwtAuth = jwt({
secret: PRIVATE_KEY,
credentialsRequired: false,
isRevoked: isRevokedCallback//传入配置项
}).unless({
path: [
], // 设置 jwt 认证白名单
});
token特性的缺失
需要注意的是token的一大特性就是无状态,也就是不用浪费存储空间和频繁的读写操作量,而当我们编写token续签时,等于是违背了token的这一特性,不过token的其他特性,比如,对避免CSRF攻击方面的自身优势还是存在的。所以要根据不同需求进行取舍
以上,如有错误,欢迎指出.
个人网站: lppwork.cn. 可以同步备忘录和添加task日历的功能网站,持续开发中...
参考资料
morgan源码. www.jianshu.com/p/2bd71c168… www.cnblogs.com/zkqiang/p/1… my.oschina.net/u/3797834/b… blog.csdn.net/qq_36850813…