JWT用户无感知刷新方案

需求: JWT用户无感知刷新,多个携带过期JWT的请求几乎同时访问不能出错,活跃用户JWT防持续盗用,单端在线。

Redis单实例实现:

每次Http请求带着JWT来访问,服务端都要按如下步骤验证/刷新令牌。

  1. 先校验JWT是否合法(只是过期,不影响校验通过) 或 数据1是否存在, 不满足任一条件,返回401,让用户重新登录。

  2. 判断数据2是否存在,存在就不需要继续验证了, 结束令牌校验,继续本次请求的业务逻辑

  3. 验证令牌是否过期,没过期结束令牌校验,继续本次请求的业务逻辑(此时,JWT合法性校验通过, 数据1存在,不存在数据2)。

  4. 令牌已过期,拿旧令牌(当前令牌),和新令牌(新生成的),调用lua脚本操作Redis刷新令牌

  5. 原子操作lua逻辑: 根据用户ID获取数据1的值,与旧令牌一致 把值换成新令牌 存入redis , 并且以旧令牌为KEY 保存数据2到redis, 返回 SUCCESS; 与旧令牌不一致(旧令牌没有刷新权限) 返回 FAIL

  6. 上一步 返回的结果是 SUCCESS,把新令牌放回http响应头中,并在http响应头中放入isnewToken标志着这是个新令牌

客户端统一拦截请求响应, 每次发送请求之前,把本地保存的令牌放到请求头里, 每次收到响应, 判断有没有isnewToken, 如果有,就把响应头中的令牌保存到本地。

redis数据结构 string

简称keyvalue有效时长(秒)说明
数据1用户ID令牌T1令牌可以无感知刷新的时长,比如:7天60*60*24*7
数据2令牌用户IDT2平滑过渡时长,比如:30秒
   /**
     * 登录/JWT过期后尝试刷新
     * @param key 用户ID
     * @param oldJwt 旧JWT
     * @param newJwt 新JWT
     * @return SUCCESS:成功, FAIL:失败
     */
    public String tryRefreshToken(String Key, String oldJwt, String newJwt) {
        String luaScript =
            "-- 根据key(用户ID)获取令牌 \n" +
            "local token = redis.call('get',KEYS[1])\n" +
            "-- 取到的token为空, 返回‘FAIL’ \n" +
            "if(not(tokens) or 0==#tokens) then return 'FAIL' end\n" +
            "-- 判断取到的token,是否与旧令牌一致 \n" +
            "-- 不一致,不能更新令牌 返回'FAIL' \n" +
            "if(token ~= ARGV[1]) then return 'FAIL' end\n" +
 "redis.call('set',KEYS[1],ARGV[2],'XX','EX',604800) \n" +
            "-- 保存平滑过渡令牌\n" +
            "redis.call('set',ARGV[1],KEYS[1],'NX','EX',30) \n" +
            "return 'SUCCESS'";

        return jedis.eval(luaScript, 1, key, oldJwt, newJwt));
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值