JWT设置过期时间隐藏的坑

JWT生成token时,设置过期时间通常如下:

  public static final int SESSION_TIME_OUT = 3600 * 24 *30;
 /**
     * 私钥加密token
     *
     * @param uid        载荷中的数据
     * @param privateKey 私钥
     * @param expire     过期时间,单位分钟
     * @return JWT
     */
    public static String buildJwtRsaToken(Long uid, PrivateKey privateKey, int expire) {
        //签发时间. 注意:尽量比当前时间稍微提前一点,防止验证时间相隔太短,导致验证不通过
        long startTime = System.currentTimeMillis() - 60;
        //过期时间. 在签发时间的基础上,加上一个时长
        Date end = new Date(startTime + SessionConstants.SESSION_TIME_OUT * 1000);  //设置过期
        Date start = new Date(startTime);  //设开始
        return Jwts.builder()
                .claim(JWT_PAYLOAD_SID, createJTI())
                .setId(String.valueOf(uid))
                .setExpiration(end)
                .setIssuedAt(start)
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .compact();

    }

执行生成token

 @Test
    public void testGenToken() throws Exception {
        String base = getBase();
        //获取当前认证的对象
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername("username");
        userDTO.setUserId(10000L);
        //获取生成token的私钥
        PrivateKey privateKey = RsaUtils.getPrivateKey(base + privateKeyFileName);
        //定义token过期时间为一天
        int expireTime = 24 * 60;
        //生成token
        String token = JwtServiceImpl.buildJwtRsaToken(userDTO.getUserId(), privateKey, expireTime);
        System.out.println("token = " + token);
    }

运行结果:

token = eyJhbGciOiJSUzI1NiJ9.eyJzaWQiOiJOR05sTW1WaE1UZ3RZMll3WXkwME9HTTRMVGczTm1ZdE1USm1PVGswTmpObVl6QTAiLCJqdGkiOiIxMDAwMCIsImV4cCI6MTcyNDQ4NDQyMywiaWF0IjoxNzI2MTg3MzkwfQ.LF7H0sI-PU3DJhqOYCVgwd1xvzriCMOTckaYdqoq2Zrsnatb5cRStNa8H0TnDa0Vrv3tJLXNfYx7omzdvRo1PK9zP7_es6jnuE8DtJhK5YMWkfAcehJgO1zDOwOWbJx9Nr5vzNTMRT6B-bLSFJbTdk18c6ka68oowq7qoozVp5GbXYayrZpllCsUyGU3xMKOqCmb487au43yNx-M7ZmUIyzXuuXGZPDoq_6QSTYRzidBwbGz8XeMMjb6o-jwVoHvwtInYQ4YMEBDFsZlaglrhdDc2NLHPpGqHtdHMEAD--lopB0nqimv6W3wUasT2xcKiWBOsVxf6ajjukfmQAg5Zw

Process finished with exit code 0

看似一切正常
校验token时就会出问题

 private String getOneToken() throws Exception {
        String base = getBase();
        //获取当前认证的对象
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername("username");
        userDTO.setUserId(10000L);
        //获取生成token的私钥
        PrivateKey privateKey = RsaUtils.getPrivateKey(base + privateKeyFileName);
        //定义token过期时间为一天
        int expireTime = 24 * 60;
        //生成token
        String token = JwtServiceImpl.buildJwtRsaToken(userDTO.getUserId(), privateKey, expireTime);
        System.out.println(token);

        return token;
    }


    @Test
    public void testCheckToken() throws Exception {
        //如果token格式正确,就验证token

        String token = getOneToken();
        //获取验证token的公钥
        String base = getBase();
        PublicKey publicKey = RsaUtils.getPublicKey(base + publicKeyFileName);

        Payload<String> payload = JwtServiceImpl.decodeJwtRsaToken(token, publicKey);

        String json = JsonUtil.pojoToJson(payload);

        System.err.println(json);
    }

执行结果如下

eyJhbGciOiJSUzI1NiJ9.eyJzaWQiOiJNV0poWlRKak0yUXRZalJpTUMwMFpXVmxMV0UyTVRjdE9URmxaVFJsTlRVM05UbGwiLCJqdGkiOiIxMDAwMCIsImV4cCI6MTcyNDQ4NDc5MSwiaWF0IjoxNzI2MTg3NzU5fQ.MQZ7tSPzo6L7pI2JYqbm7yroMIGwiBcWNue9hf24XlSN4vN5NB4nRuj59-d5u5cNgww49Rz98g-_P6vU-g2U3aoC7HizZ0_BWMRzsmosMWp9aKqztG5Dh_qiqs3NcF1p8npaJzZY6Oi8io1GT9Fem82H4eh56dItRy7T75mgzdvJjQIRBZyDwyktFzeVOwMHRcMnvAw10gefPb1QDa-QK-oK_XbGtO0dgiPei-kLdNZxY7SXRMgOhUIHCC15_QSjDDyOGOKHJI0l5Z7or7zz06g1edWLr9nMKrIlO2Re6KQ82Tw7pvFRTj-KJlEQZmHmD5L6UficlKktPOu6hpZJ5A
io.jsonwebtoken.ExpiredJwtException: JWT expired at 2024-08-24T07:33:11Z. Current time: 2024-09-13T00:36:00Z, a difference of 1702969788 milliseconds.  Allowed clock skew: 0 milliseconds.
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:411)
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:513)
	at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:573)
	at com.crazymaker.springcloud.base.service.impl.JwtServiceImpl.parseJwtRsaToken(JwtServiceImpl.java:158)
	at com.crazymaker.springcloud.base.service.impl.JwtServiceImpl.decodeJwtRsaToken(JwtServiceImpl.java:104)
	at com.crazymaker.springcloud.test.sso.JwtRsaTest.testCheckToken(JwtRsaTest.java:143)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)

业务异常
BusinessException(errCode=-1, errMsg=token 验证异常)
	at com.crazymaker.springcloud.common.exception.BusinessException$Builder.build(BusinessException.java:61)
	at com.crazymaker.springcloud.base.service.impl.JwtServiceImpl.parseJwtRsaToken(JwtServiceImpl.java:162)
	at com.crazymaker.springcloud.base.service.impl.JwtServiceImpl.decodeJwtRsaToken(JwtServiceImpl.java:104)
	at com.crazymaker.springcloud.test.sso.JwtRsaTest.testCheckToken(JwtRsaTest.java:143)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)


Process finished with exit code -1

看问题的描述:

JWT expired at 2024-08-24T07:33:11Z. Current time: 2024-09-13T00:36:00Z, a difference of 1702969788 milliseconds.  Allowed clock skew: 0 milliseconds.

过期时间为2024-08-24T07:33:11,当前时间为2024-09-13T00:36:00,token过期了,但是我明明是获取token后马上执行的解密,那么问题应该在设置过期时间
定位相关代码:

 /**
     * session 的过期时间  单位 s
     */
    public static final int SESSION_TIME_OUT = 3600 * 24 *30;
  //签发时间. 注意:尽量比当前时间稍微提前一点,防止验证时间相隔太短,导致验证不通过
        long startTime = System.currentTimeMillis() - 6000;
        //过期时间. 在签发时间的基础上,加上一个时长
        Date end = new Date(startTime + SessionConstants.SESSION_TIME_OUT * 1000);  //设置过期

看着没啥问题,过期时间是在当前时间上加的,而且这个时间设置得挺长的。
那么问题是什么啦?
打印这个过期时间

System.out.println(SessionConstants.SESSION_TIME_OUT * 1000);

先问问chatgpt:
在这里插入图片描述
他给的回答看不出问题
最后自己执行下:

-1702967296

拿着结果再问问他
在这里插入图片描述
原来当你尝试计算2592000 * 1000时,实际的结果2592000000已经超出了int类型的最大值。因此,在Java中,这个计算会导致整数溢出,而溢出的结果是一个负数,即你看到的-1702967296。
问题解决了
总结下:
1.int的大数计算要小心整数溢出的问题
2.不要盲目信任chatgpt,有问题还是需要自己代码执行下,拿着结果再去问问题

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值