在比较 jwt.iat(发布于)属性与当前日期时间时遇到问题 - (“自纪元以来的秒数”NumericDate)

Posted

技术标签:

【中文标题】在比较 jwt.iat(发布于)属性与当前日期时间时遇到问题 - (“自纪元以来的秒数”NumericDate)【英文标题】:having troubles comparing jwt.iat (issued at) property with current datetime - ("Seconds Since the Epoch" NumericDate) 【发布时间】:2020-02-26 02:16:45 【问题描述】:

我从 Web 服务获取 json Web 令牌,解码后返回如下内容:


  "exp": 1572468916,
  "iat": 1572468316,
  "iss": "https://ccc/auth/realms/yyy",
  "aud": "xxx-api",
  [...]

根据Section 2 terminalogy,NumericDate 数据类型对应于“Seconds since the Epoch”

所以我将它转换为这样的 javascript 日期:

new Date(1572468316 * 1000)
Date Wed Oct 30 2019 17:45:16 GMT-0300 (Argentina Standard Time)

问题是我现在的时间是:

new Date()
Date Wed Oct 30 2019 14:45:19 GMT-0300 (Argentina Standard Time)

实际上,当前时间是从new Date() 返回的时间(即14:45,不是17:45)

我猜这与格林威治标准时间有关,但我不知道如何处理。

我想将 iat 属性(当然也包括 exp 属性)转换为当前时间,以便将其与 new Date() 进行比较,以确定令牌是否已经过期。

那么如何将来自 json Web 令牌 iat/exp 属性的 NumericDate 转换为我的本地时间以进行比较?

【问题讨论】:

也许尝试从时间戳中减去 3 小时的秒数?更动态地,您可以使用(new Date()).getTimezoneOffset() 来获取您距 GMT 的分钟数,然后减去 60 次。让我知道这是否有效;如果是这样,我会把它作为官方答案发布。 我可以确认该方法可以正常工作,为了使其通用,我必须将 NumericDate 转换为日期,然后提取 getTimezonOffset,如下所示:const d_utc = new Date(1572468316 * 1000) 然后const d_local = new Date(d_utc.valueOf() - (d_utc.getTimezoneOffset() * 60 * 1000)) 这样 d_utc = Date Wed Oct 30 2019 17:45:16 GMT-0300 (Argentina Standard Time) 和 d_local = Date Wed Oct 30 2019 14:45:16 GMT-0300 (Argentina Standard Time) 继续发布我可以接受的答案;-) 抱歉,这不是正确的方法。我将发布一个简短的答案来解释。 【参考方案1】:

iatexp 值确实以 Unix 纪元以来的秒数为单位。由于 Unix 纪元是基于 UTC 的,因此这些值也是如此。您正在正确地将它们转换为 Date 对象。

var iat = new Date(1572468316 * 1000);
var exp = new Date(1572468916 * 1000);

console.log(iat.toISOString()); //=> "2019-10-30T20:45:16.000Z"
console.log(exp.toISOString()); //=> "2019-10-30T20:55:16.000Z"

toISOString 函数发出一个 ISO 8601 格式的字符串,表示为 UTC(由结尾的 Z 字符表示)。

您在问题中给出的输出格式是在调用toString 函数或在选择记录toString 输出的环境中直接记录Date 对象时会发生什么。由于不同的环境可以发出不同的格式(有些是当地时间,有些是 UTC,有些是 ISO 8601,有些是非标准格式) - 不建议直接记录 Date 对象。

toISOString 的输出显示 JWT 的有效期为 10 分钟,从 2019 年 10 月 30 日 20:45:16 UTC 到 2019 年 10 月 30 日 20:55:16 UTC。没有其他方法可以解释这些结果。

您的本地时间输出显示三个小时的转换,这将正确对应于 UTC-3 时区偏移,再次确认它们的值被正确解析。

如果这不是您所期望的,那么令牌没有正确发出。正在发生以下两种情况之一:

生成 JWT 的代码中可能存在错误,因为它使用本地时间而不是 UTC 作为创建时间戳的基础。

运行生成 JWT 的代码的服务器的时钟设置可能不正确。

第二个更合理。例如,当服务器管理员将时区设置为 UTC 但根据本地时间设置时钟时,可能会发生这种情况。相反,请确保将服务器上的时钟设置为自动从 Internet 同步其时间,这样问题就可能会消失。

关于问题 cmets 中提到的方法 - 不要这样做。以这种方式减去时区偏移量并不能正确调整时区,而是选择不同的时间点。它可能看起来提供了正确的结果,但您会发现许多时区的夏令时转换的边缘情况,一旦开始使用正确的值生成 JWT,您就会遇到问题。

【讨论】:

很好的答案,Web 服务工作正常,您能否在答案中添加比较 exp NumericDate 值与我的本地时间比较令牌是否已过期的最佳方法?我尝试将其与new Date().getTime() 进行比较,但我仍然有 3 小时的差异 这是比较的正确方法(将秒调整为毫秒后)。如果您休息三个小时,则说明您的本地时钟设置错误,或者发出 JWT 的服务器的时钟设置错误或编码错误。 为什么需要将iat1000 相乘? var iat = new Date(1572468316 * 1000); 因为1572468316 为单位,而Date 构造函数需要毫秒。 (1000 毫秒是 1 秒)

以上是关于在比较 jwt.iat(发布于)属性与当前日期时间时遇到问题 - (“自纪元以来的秒数”NumericDate)的主要内容,如果未能解决你的问题,请参考以下文章

从firestore查询数据时,如何将保存的字符串格式的日期与当前日期进行比较?

如何在javascript中将当前日期时间与另一个日期时间进行比较

java输入的日期与当前的日期做比较?

将输入类型日期与当前日期进行比较

python所有版本发布时间?

将日期和时间与 MySQL 中的当前时间进行比较