【问题标题】:Check if token expired using this JWT library使用此 JWT 库检查令牌是否过期
【发布时间】:2018-12-19 21:41:18
【问题描述】:

我已经像这样配置了令牌:

jwt.sign(
  {
    user: pick(user, ['_id', 'username'])
  },
  secret,
  {
    expiresIn: '2m'
  }
);

但是当我想检查令牌是否过期时,这段代码不起作用:

function isAuthenticated() {
  const token = localStorage.getItem('token');
  const refreshToken = localStorage.getItem('refreshToken');
  try {
    decode(token);
    const { exp } = decode(refreshToken);
    if (exp < (new Date().getTime() + 1) / 1000) {
      return false;
    }
  } catch (err) {
    return false;
  }
  return true;
}

问题出在这部分:

if (exp < (new Date().getTime() + 1) / 1000) {
  return false;
}

new Date().getTime() + 1) / 1000 = 1531335468.113

exp = 1531334595

因为我不知道 JWT 使用什么格式的时间...

我该如何解决这个问题?

【问题讨论】:

  • 打印“new Date().getTime() + 1”的输出,请发帖。
  • 你是如何解码令牌的?如果您使用的是库,它将自动验证令牌的到期时间(默认情况下)。例如。 jsonwebtoken:github.com/auth0/…
  • @RamonSnir 与库 jsonwebtoken
  • @AndrésMontoya 为什么不使用 jwt.verify 而不是 jwt.decode? jwt.decode 甚至不验证令牌是否正确签名。
  • @RamonSnir 我在浏览器上使用jwt-decode,在服务器上使用jsonwebtoken,isAuthenticated函数来自客户端

标签: javascript node.js express jwt


【解决方案1】:

这就是答案:

if (Date.now() >= exp * 1000) {
  return false;
}

【讨论】:

  • 有缺陷,因为 now() 使用时区
  • @lony 没有缺陷,Date.now() 和 JWT 过期时间都标识自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的时间。
  • 返回 false 是否意味着令牌已过期?
  • @kritiz 是的。基本上,如果 Date.now() 以毫秒为单位大于或等于过期时间(转换为毫秒)。
  • 你是福。谢谢。
【解决方案2】:

您应该使用jwt.verify。它会检查令牌是否过期。

如果源不受信任,则不应使用jwt.decode,因为它不会检查令牌是否有效。

【讨论】:

  • isAuthenticated 函数在前端工作。无论如何,解决方案已为我评论...
  • 哦,好的,但您没有收到带有令牌的expiresIn
  • 但是exp的目的是什么?
  • @Roel exp 用于前端,用于设置超时并注销用户或刷新令牌。我不知道我们可以简单地使用 jwt.verify 来检查令牌是否已过期。它在文档中声明:“如果签名有效并且可选的到期、受众或发行者有效,则使用解码的有效负载调用回调。如果不是,它将被错误地调用。”,所以我们可以简单地使用if (jwt.verify(token, secret) 来验证它是否已经过期。
【解决方案3】:

verify 本身在过期时返回错误。 Gabriel said 更安全。

const jwt = require('jsonwebtoken')

router.use((req, res, next) => {
  const token = yourJwtService.getToken(req) // Get your token from the request
  jwt.verify(token, req.app.get('your-secret'), function(err, decoded) {
    if (err) throw new Error(err) // Manage different errors here (Expired, untrusted...)
    req.auth = decoded // If no error, token info is returned in 'decoded'
    next()
  });
})

同样写在async/await语法中:

const jwt = require('jsonwebtoken')
const util = require('util');
const jwtVerifyAsync = util.promisify(jwt.verify);

router.use(async (req, res, next) => {
  const token = yourJwtService.getToken(req) // Get your token from the request
  try {
    req.auth = await jwtVerifyAsync(token, req.app.get('your-secret')) // If no error, token info is returned
  } catch (err) {
    throw new Error(err) // Manage different errors here (Expired, untrusted...)
  }
  next()
});

【讨论】:

    【解决方案4】:

    没有jwt 库的函数:

    浏览器

    function isTokenExpired(token) {
      const base64Url = token.split(".")[1];
      const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
      const jsonPayload = decodeURIComponent(
        atob(base64)
          .split("")
          .map(function (c) {
            return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
          })
          .join("")
      );
    
      const { exp } = JSON.parse(jsonPayload);
      const expired = Date.now() >= exp * 1000
      return expired
    }
    

    或者更简单

    function isTokenExpired(token) {
      const expiry = (JSON.parse(atob(token.split('.')[1]))).exp;
      return (Math.floor((new Date).getTime() / 1000)) >= expiry;
    }
    

    或单线:

    const isTokenExpired = token => Date.now() >= (JSON.parse(atob(token.split('.')[1]))).exp * 1000
    

    Node.js

    function isTokenExpired(token) {
      const payloadBase64 = token.split('.')[1];
      const decodedJson = Buffer.from(payloadBase64, 'base64').toString();
      const decoded = JSON.parse(decodedJson)
      const exp = decoded.exp;
      const expired = (Date.now() >= exp * 1000)
      return expired
    }
    

    或单线:

    const isTokenExpired = (token) => (Date.now() >= JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).exp * 1000)
    

    【讨论】:

    • 非常有趣!谢谢你的分享:)。
    • 干得好。做得好。非常感谢。
    【解决方案5】:

    可悲的是,Andrés Montoya's answer 有一个缺陷,这与他如何比较对象有关。

    我找到了一个解决方案 here 应该可以解决这个问题:

    const now = Date.now().valueOf() / 1000
    
    if (typeof decoded.exp !== 'undefined' && decoded.exp < now) {
        throw new Error(`token expired: ${JSON.stringify(decoded)}`)
    }
    if (typeof decoded.nbf !== 'undefined' && decoded.nbf > now) {
        throw new Error(`token expired: ${JSON.stringify(decoded)}`)
    }
    

    感谢用户thejohnfreeman

    【讨论】:

      【解决方案6】:

      以下函数无需任何库即可工作:

      function getJWTExpireDate(jwtToken: string) {
        if (jwtToken) {
          try {
            const [, payload] = jwtToken.split('.');
            const { exp: expires } = JSON.parse(window.atob(payload));
            if (typeof expires === 'number') {
              return new Date(expires * 1000);
            }
          } catch {
            // ignore
          }
        }
        return null;
      }
      

      不要使用它来检查令牌是否有效。一个很好的用例是在前端显示令牌过期时。

      【讨论】:

        【解决方案7】:

        这适用于React Native,但登录适用于所有类型。

        isTokenExpired = async () => {
            try {
                const LoginTokenValue = await AsyncStorage.getItem('LoginTokenValue');
                if (JSON.parse(LoginTokenValue).RememberMe) {
                    const { exp } = JwtDecode(LoginTokenValue);
                    if (exp < (new Date().getTime() + 1) / 1000) {
                        this.handleSetTimeout();
                        return false;
                    } else {
                        //Navigate inside the application
                        return true;
                    }
                } else {
                    //Navigate to the login page
                }
            } catch (err) {
                console.log('Spalsh -> isTokenExpired -> err', err);
                //Navigate to the login page
                return false;
            }
        }
        

        【讨论】:

          【解决方案8】:

          您可以使用 jwt 验证方法来检查令牌的有效性。 err 表示令牌已过期并会抛出错误,因此您可以删除存储的令牌。

           jwt.verify(token, SECRET, (err, decoded) => {
                if (err) {
                    localStorage.clear();
                }}
            });
          

          【讨论】:

          • 嗨,如何才能删除该用户的特定令牌,因为获取用户的信息存储在令牌中,因为它会引发错误,所以我无法获取?
          【解决方案9】:
          // Pass in function expiration date to check token 
          function checkToken(exp) {
              if (Date.now() <= exp * 1000) {
                console.log(true, 'token is not expired')
              } else { 
                console.log(false, 'token is expired') 
              }
            }
          

          【讨论】:

            猜你喜欢
            • 2018-06-19
            • 2017-07-29
            • 2016-08-16
            • 2020-06-30
            • 2021-12-21
            • 2014-12-19
            • 1970-01-01
            • 2023-04-04
            • 2020-09-29
            相关资源
            最近更新 更多