禁用token及无感知更新token功能实现

禁用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)
    });
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值