PassportJS 验证过期的 JWT

Joe*_*Tea 0 javascript jwt passport.js

我的问题的关键是PassportJS 似乎正在验证 JWT,当当前时间超过 exp 参数时,该 JWT 应该是无效的

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

代码

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

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

// ...
Run Code Online (Sandbox Code Playgroud)
// 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,
  };
};
Run Code Online (Sandbox Code Playgroud)
// 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);
        }
      });
    })
  );
};
Run Code Online (Sandbox Code Playgroud)
// 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
  );
Run Code Online (Sandbox Code Playgroud)
// 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);
  }
};
Run Code Online (Sandbox Code Playgroud)

示例有效负载

{
 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]
Run Code Online (Sandbox Code Playgroud)

我期望发生什么

  1. 客户端将 GET 请求发送到 /authenticate-with-access-token,并在 auth 标头中使用承载令牌 (JWT)
  2. PassportJS(通过jsonwebtoken.verify())尝试验证 JWT,但发现Date.now()超过了 JWT 的到期时间
  3. PassportJS 引发错误,并使用 401 Unauthorized 响应解决请求

发生了什么

  1. 客户端将 GET 请求发送到 /authenticate-with-access-token,并在 auth 标头中使用承载令牌 (JWT)
  2. PassportJS 将用户对象传递到请求正文中并调用next()
  3. 最后一个中间件运行,使用 200 OK 响应解析请求,并通过 JSON 正文传回用户详细信息

我确信我错过了一些明显的事情,但我一生都无法弄清楚发生了什么。感谢您提前提供任何帮助!

Joe*_*Tea 5

好吧,我想通了!

事实证明(通过查看 jsonwebtoken 文档上的示例),签署令牌时使用的 iat 属性应该以秒为单位,而不是毫秒。因此Date.now()tokens.js 中的内容实际上应该是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,
  };
};
Run Code Online (Sandbox Code Playgroud)