当前位置:网站首页>禁用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)
});
}
边栏推荐
猜你喜欢
随机推荐
6-接口跨域处理
WRF-Chem模式调试、运行、结果后处理等遇到的各种问题
46LVS+Keepalived群集
向往的生活
MATLAB绘制填充图(X轴上下两种颜色)
增删改查这么多年,最后栽在MySQL的架构设计上!
高并发基石:多线程、守护线程、线程安全、线程同步、互斥锁,一文扫尽!...
能添加任意贴图超级复布局的初级智能文本提示器
JSP第一篇 -----JSP九大内置对象(隐式对象)和四大域对象
Qt在选择MSVC 编译器的时候,无法识别出M_PI的问题处理
五大靠谱的婚恋相亲APP详细特点缺点分析!
公司代码学习笔记
【社媒营销】Facebook速推帖子如何运作?值得吗?
投资的思考
mysql binlog日期解析成yyyy-MM-dd
怎么从零编写一个 v3 版本的 chrome 浏览器插件实现 CSDN 博客网站的暗黑和明亮主题切换?
全栈----跨域
ES6 新特性:Class 的基本语法
visual studio 2012 为啥这么优秀
php一维数组合并