为了账号安全,请及时绑定邮箱和手机立即绑定

在 UTC 中使用过期日期时 JWT 过期不起作用

在 UTC 中使用过期日期时 JWT 过期不起作用

慕田峪9158850 2022-11-30 16:07:53
我正在使用jjwtjwt 令牌创建。使用本地系统时间设置到期日期时一切正常,即日期 expDate = new Date(new Date().getTime() + 180000); //java.util.日期但我尝试使用 UTC 格式日期时间并使用相同的 3 分钟到期日期签署 jwt 令牌。现在它正在抛出ExpiredJwtException,尽管我在创建令牌后立即进行验证。我正在使用 SimpleDateFormat 将时区设置为 utc。这是我在 java 中使用 jjwt 创建令牌的代码:    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    Date expDate, issDate;    try {        expDate = (Date) simpleDateFormat.parse(sdf.format(new Date().getTime() + 180000));        issDate = (Date) simpleDateFormat.parse(sdf.format(new Date().getTime()));        JwtBuilder builder = Jwts.builder()                .setExpiration(expDate)                .setIssuedAt(issDate)                .setId(id)                .signWith(signingKey, signatureAlgorithm);        jwtToken = builder.compact();    } catch (ParseException ex) {    }令牌已成功创建。我也可以在线验证内容。expDate 比 issDate 早 3 分钟。我还在通过传递创建的令牌创建令牌后立即调用验证令牌的方法。我的验证方法有:    try {        Jwts.parser().setSigningKey(signingKey).parseClaimsJws(token);        log.info("jwt verification success");    } catch (ExpiredJwtException exJwt) {        log.info("expired jwt : \n{}", exJwt.getMessage());    } catch (JwtException e) {        log.info("tampered jwt");    }但我越来越ExpiredJwtException。错误是expired jwt :JWT 在 2019-05-17T01:24:48Z 过期。当前时间:2019-05-17T07:06:48Z,相差20520836毫秒。允许的时钟偏差:0 毫秒。从我的日志来看,此时我的token中的签发日期和到期日期是:issued date is: 2019-05-17T07:06:48.000+0545expiry date is: 2019-05-17T07:09:48.000+0545这是怎么回事?谢谢你的帮助。
查看完整描述

1 回答

?
呼啦一阵风

TA贡献1802条经验 获得超6个赞

这里不需要SimpleDateFormat,as表示自Unix EpochDate以来的毫秒数,即 1970 年 1 月 1 日午夜(UTC)。

然而,可能导致混淆的是方法toString()因为它在生成表示该值的字符串时应用 JVM 的默认时区。

由于您担心 UTC,让我提醒您注意协调世界时 (UTC) 实际上是什么:它是一个时间标准(而不是时区),它由高精度原子钟和地球自转决定。

UTC 时间标准经过多次调整,直到 1972 年引入闰秒以使 UTC 与地球自转保持一致,地球自转并不完全均匀,而且不如原子钟精确。随着地球自转速度的减慢,我们不得不时不时地在各处插入闰秒:

//img1.sycdn.imooc.com//63870f9f00010d1405730288.jpg

虽然 的内部值Date旨在反映 UTC,但由于那些闰秒,它可能不会完全这样做。

Java 8 和日期和时间的新 API

即使Date在涉及 UTC 时适合您的需求,您也应该避免使用它。现在是遗留类

Java 8为基于 ISO 日历系统的日期、时间、瞬间和持续时间引入了新的 API 。最接近的等价物DateInstant代表时间戳,UTC 时间线上的时刻。

要以 UTC 格式捕获当前时刻,您可以使用以下命令:

Instant.now();              // Capture the current moment in UTC

您可以使用以下内容来获取表示此类值的字符串:

Instant.now().toString();   // 2019-05-17T12:50:40.474Z

此字符串根据ISO 8601进行格式化,其中Z指示给定时间为 UTC。

与 JJWT 的互操作性

对于尚不支持类型的JJWT 的互操作性java.time,您可以创建Datefrom的实例Instant

Date.from(Instant.now());   // Convert from modern class to legacy class

这是一个演示如何发布和验证令牌的测试:

@Test

public void shouldMatchIssuedAtAndExpiration() {


    Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);


    Instant issuedAt = Instant.now().truncatedTo(ChronoUnit.SECONDS);

    Instant expiration = issuedAt.plus(3, ChronoUnit.MINUTES);


    log.info("Issued at: {}", issuedAt);

    log.info("Expires at: {}", expiration);


    String jws = Jwts.builder()

            .setIssuedAt(Date.from(issuedAt))

            .setExpiration(Date.from(expiration))

            .signWith(key)

            .compact();


    Claims claims = Jwts.parser()

            .setSigningKey(key)

            .parseClaimsJws(jws)

            .getBody();


    assertThat(claims.getIssuedAt().toInstant(), is(issuedAt));

    assertThat(claims.getExpiration().toInstant(), is(expiration));

}

对于上面的示例,我使用了 JJWT 0.10.5 以及文档中列出的依赖项。如果您需要,上面的代码是用以下import语句编写的:


import io.jsonwebtoken.Claims;

import io.jsonwebtoken.Jwts;

import io.jsonwebtoken.SignatureAlgorithm;

import io.jsonwebtoken.security.Keys;

import lombok.extern.slf4j.Slf4j;

import org.junit.Test;


import java.security.Key;

import java.time.Instant;

import java.time.ZoneOffset;

import java.time.temporal.ChronoUnit;

import java.util.Date;


import static org.hamcrest.CoreMatchers.is;

import static org.junit.Assert.assertThat;


查看完整回答
反对 回复 2022-11-30
  • 1 回答
  • 0 关注
  • 114 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信