当前位置:网站首页>禁用token及无感知更新token功能实现
禁用token及无感知更新token功能实现
2022-08-03 01:42:00 【qishaoawei】
禁用token
禁用token通俗的讲就是将登录后保存到浏览器上的token退出登录时也保存到redis里
然后利用钩子函数在每次请求前都判断一次,如果再次请求的token与redis里的token进行对比
如果两者一直说明token没有更新,很可能是token泄露被人恶意使用,
所以每次退出都要禁用token
紧接着强制登录后 实现禁用token
在项目内蓝图中创建
@user_dp.before_app_request
def gz(): #钩子函数 每次请求前都调用
rep = reqparse.RequestParser()
rep.add_argument('token', location='headers')
args = rep.parse_args()
token = args['token']
payload = JwtTool().valid(token) #解密token
## 放入钩子函数里验证token是否存在
rds = SmsTool().rds # 已经封装好的redis数据库信息
is_exists = rds.exists('token_%s' % token)
rds.close()
if is_exists:
g.uid = -1
else:
try:
g.uid=payload['uid']
except Exception as a:
print(a)
g.uid=0
def login(func):
def warpper(*args,**kwargs):
#判断用户是否登录
uid=g.uid
if uid==0:
return jsonify({
'code':403,
'msg':'用户未登录'
})
elif uid==-1: #验证token是否在redis里面
return jsonify({
'code':400,
'msg':'token被禁用'
})
return func(*args,**kwargs)
return warpper
#退出登录 前端退出登录先调用这个 然后再清空token
class TokenView(Resource):
@login
def post(self):
rep = reqparse.RequestParser()
rep.add_argument('token', location='headers')
args = rep.parse_args()
token = args['token']
rds=SmsTool().rds #已经封装好的redis数据库信息
rds.set('token_%s'%token,'1',ex=3600)
rds.close()
return jsonify({
'code':200,
'msg':'退出成功'
})
api.add_resource(TokenView,'/token') #退出
无感知更新token
无感知更新token就是token的有效期不长才安全,就需要频繁的更新,让它自己更新就简单很多
在登录的蓝图中进行编写
@user_dp.before_app_request
def gz():
rep = reqparse.RequestParser()
rep.add_argument('token', location='headers')
args = rep.parse_args()
token = args['token']
payload = JwtTool().valid(token)
## 放入钩子函数里验证token是否存在
rds = SmsTool().rds # 已经封装好的redis数据库信息
is_exists = rds.exists('token_%s' % token)
rds.close()
if is_exists:
g.uid = -1
else:
try:
g.uid=payload['uid']
except ExpiredSignatureError:
g.uid=-2 #如果有其他的报错就是-2
except Exception as a:
print(a)
g.uid=0
def login(func):
def warpper(*args,**kwargs):
#判断用户是否登录
uid=g.uid
if uid==0:
return jsonify({
'code':403,
'msg':'用户未登录'
})
elif uid==-1: #验证token是否在redis里面
return jsonify({
'code':400,
'msg':'token被禁用'
})
elif uid==-2: #验证是否已过期
return jsonify({
'code':666,
'msg':'token已过期'
})
return func(*args,**kwargs)
return warpper
class LoginView(Resource): #登录
def post(self):
rep=reqparse.RequestParser()
rep.add_argument('phone')
rep.add_argument('password')
args=rep.parse_args()
user_info=UserModel2.query.filter(UserModel2.mobile==args['phone']).first()
if not user_info:
return jsonify({
'code':400,
'msg':'该用户手机号不存在'
})
if user_info.password!=args['password']:
return jsonify({
'code':400,
'msg':'密码不正确'
})
token=JwtTool().create({
#短token
'username':user_info.username,
'uid':user_info.id,
'exp':int(time.time()+360) #加上一个有效期360秒
})
long_token=JwtTool().create({
#长token
'username':user_info.username,
'uid':user_info.id,
'long':True, #这个标志是用来区分长token的 目的是让token不能进行普通接口的校验 只用于特定接口的校验
'exp':int(time.time()+15*24*3600) #加上一个有效期15天
})
return jsonify({
'code':200,
'msg':'登陆成功',
'data':{
'username':user_info.username,
'token':token, #短token #登录的时候两个都保存
'long_token':long_token #长token
}
})
#退出登录 前端退出登录先调用这个 然后再清空token
class TokenView(Resource):
def put(self): #更新token
#获取参数
rep = reqparse.RequestParser()
rep.add_argument('longtoken', location='headers')
args = rep.parse_args()
#校验参数
try:
payload=JwtTool().valid(args['longtoken']) #封装的解密token
except Exception as a:
return jsonify({
'code':403,
'msg':'用户未登录'
})
#逻辑
user_info = UserModel2.query.get(payload['uid'])
#再生成token
token = JwtTool().create({
# 利用封装的生成token函数
'username': user_info.username,
'uid': user_info.id,
'exp': int(time.time() + 360) # 加上一个有效期360秒
})
#返回响应
return jsonify({
'code':200,
'msg':'token更新成功',
'data':{
'token':token
}
})
前端在main.js里进行编写
//强制登录
axios.interceptors.response.use(function(resp){
console.log('resp===',resp) //resp 就是请求响应回来的数据
// 未登录用户 直接跳转到登录页面
if(resp.data.code==403){
router.push('/login') //此处无法使用 this.$router
}
return resp //把请求对象返回回去
},function(error){
console.log(error)
})
// 无感知更新token
axios.interceptors.response.use(function(resp){
console.log(resp)
if(resp.data.code==666){
// 代表token过期了
//重新请求token
reloadToken()
}
return resp
},function(error){
console.log(error)
})
//重新加载token
function reloadToken(){
axios.put('/user/token',{
},{
'headers':{
'longtoken':localStorage.getItem('long_token')
}
}).then((result) => {
if (result.data.code==200){
localStorage.setItem('token',res.data.data.token)
window.location.reload() //网页刷新
}
}).catch((err) => {
console.log(err)
});
}
边栏推荐
猜你喜欢

[Example构造方法增加notNull参数,默认false,允许值为null,值为null的时候不加入到条件中

iNFTnews | 元宇宙的潜力:一股推动社会进步的力量

.NET深入解析LINQ框架(四:IQueryable、IQueryProvider接口详解)

国标GB28181协议EasyGBS平台项目现场通知消息过多导致系统卡顿该如何解决?

新库上线 | CnOpenDataA股上市公司董监高信息数据

【Swoole系列3.3】单进程管理Process

10. SAP ABAP OData 服务如何支持修改(Update)操作

apache-activemq-5.14.1

作业8.2 线程同步互斥机制——互斥锁

Greenplum database failure analysis, can not listen to the port
随机推荐
SAP ABAP Gateway Client 里 OData 测试的 PUT, PATCH, MERGE 请求有什么区别
不想当Window的Dialog不是一个好Modal,弹窗翻身记...
全栈---CORS
pytest:如何调用 pytest
梅科尔工作室-14天华为培训三
自定义RunTimeException工具类
XSS攻击
有趣简单的M2处理器性能实验:Swift与C代码执行速度的比较
面试题整理1
12-security退出.md
Wireshark data capture and analysis of the transport layer protocol (TCP protocol)
数据中台建设(八):数据服务体系建设
新库上线 | CnOpenDataA股上市公司董监高信息数据
apache-activemq-5.14.1
项目管理到底管的是什么?
大厂标配 | 百亿级并发系统设计 | 学完薪资框框涨
OpenWRT设置ipv6网络
List转Map的几种方式
LabVIEW程序框图保存为图像
Greenplum database failure analysis, can not listen to the port