Passport JS 验证过期的 JWT

PassportJS Validates Expired JWT

我的问题的症结在于 PassportJS 似乎正在验证一个 JWT,它应该是无效的,因为当前时间超过了 exp 参数

我已经提供了相关的代码片段并解释了我认为应该发生的事情(尽管显然不是!!)

密码

// In server.js
// ...
const passport = require("passport");
// ...

require("./config/passport")(passport);
app.use(passport.initialize());

// ...
// In token.js (used to issue JWT)
const jsonwebtoken = require("jsonwebtoken");
// ...

const issueJWT = (user) => {
  const _id = user._id;
  const expiresIn = 30000; // 30s for testing purposes
  const payload = {
    sub: _id,
    iat: Date.now(),
  };

  const signedToken = jsonwebtoken.sign(payload, PRIV_KEY, {
    expiresIn: expiresIn,
    algorithm: "RS256",
  });

  return {
    token: "Bearer " + signedToken,
    expires: expiresIn,
  };
};
// In passport.js
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
// ...

const options = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: PUB_KEY,
  algorithms: ["RS256"],
};

module.exports = (passport) => {
  passport.use(
    new JwtStrategy(options, (jwt_payload, done) => {
      User.findOne({ _id: jwt_payload.sub }, (err, user) => {
        if (err) {
          return done(err, false);
        }
        if (user) {
          return done(null, user);
        } else {
          return done(null, false);
        }
      });
    })
  );
};
// In routes.js
// ...
const passport = require("passport");
const { authenticateWithAccessToken } = require("../controllers/usersController");
// ...
router
  .route("/authenticate-with-access-token")
  .get(
    passport.authenticate("jwt", { session: false }),
    authenticateWithAccessToken
  );
// In usersController.js
exports.authenticateWithAccessToken = async (req, res, next) => {
  try {
    const user = req.user;

    res.status(200).json({
      success: true,
      name: user.name,
      email: user.email,
    });
  } catch (err) {
    next(err);
  }
};

有效负载示例

{
 alg: "RS256",
 typ: "JWT"
}.
{
 sub: "5eec9f1c4a416c1e50fc0a8e", // user._id
 iat: 1593258411458,              // 2020-06-27 11:46:51
 exp: 1593258441458               // 2020-06-27 11:47:21
}.
[signature]

我希望发生的事情

  1. 客户端在 auth header
  2. 中使用不记名令牌 (JWT) 向 /authenticate-with-access-token 发送 GET 请求
  3. PassportJS(通过 jsonwebtoken.verify())尝试验证 JWT,但发现 Date.now() 超过了 JWT
  4. 的到期时间
  5. PassportJS 引发错误,使用 401 未授权响应解决请求

发生了什么

  1. 客户端在 auth header
  2. 中使用不记名令牌 (JWT) 向 /authenticate-with-access-token 发送 GET 请求
  3. PassportJS 将用户 object 传递到请求 body 并调用 next()
  4. 中间件的最后一块运行,用 200 OK 响应解析请求并通过 JSON body
  5. 传回用户详细信息

我确定我遗漏了一些明显的东西,但对于我来说,我无法弄清楚发生了什么。提前感谢您的帮助!

我认为你应该在 options 对象中设置 jwt 标记的 Maxage 由于 passport 正在使用 jsonwebtoken 模块验证令牌,如果您将 ignoreExpiration 选项设置为 true passport 将不会验证令牌的 expritation,我知道情况并非如此,因为我看不到它在你的代码中,但我最好的猜测是你必须在你的选项中设置 Maxage 像这样 { expiresIn: '1h' }

来自 documentation

jsonWebTokenOptions: passport-jwt is verifying the token using jsonwebtoken. Pass here an options object for any other option you can pass the jsonwebtoken verifier. (i.e maxAge)

如果您想了解有关 jsonwebtoken

的更多信息

好的,我明白了!

事实证明(通过查看 jsonwebtoken 文档中的示例)签署令牌时使用的 iat 属性 应该以秒而不是毫秒为单位。因此 tokens.js 中的 Date.now() 实际上应该是 Math.floor(Date.now / 1000):

// In token.js (used to issue JWT)
const jsonwebtoken = require("jsonwebtoken");
// ...

const issueJWT = (user) => {
  const _id = user._id;
  const expiresIn = 30; // 30s for testing purposes

  const payload = {
    sub: _id,
    iat: Math.floor(Date.now() / 1000),
  };

  const signedToken = jsonwebtoken.sign(payload, PRIV_KEY, {
    expiresIn: expiresIn,
    algorithm: "RS256",
  });

  return {
    token: "Bearer " + signedToken,
    expires: expiresIn,
  };
};