【问题标题】:Is it better to keep just the user_id or the whole user object in the payload when signing a jwt?在签署 jwt 时,只保留 user_id 或整个用户对象是否更好?
【发布时间】:2021-01-30 11:19:15
【问题描述】:

我知道有两种方法。

1) 传递整个用户对象:

let payload = {
    user: {
      id: user._id,
      name:user.name,
      email:user.email, 
      username:user.username
    },
  }

let token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1d' })

2) 仅传递 _id:

let token = jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
    expiresIn: '1d',
});

在第二种方法中,每当我想访问受保护的路由时,我都必须使用存储在有效负载中的 _id 进行数据库调用以获取用户的详细信息。

// protect.js
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET);

req.user = await User.findById(decoded.id);

虽然在第一种方法中,我始终拥有完整的用户详细信息对象,而无需进行额外的数据库调用。

在阅读了几篇博客之后,我开始知道我们应该保持我们的负载轻量级,但我心中的问题是,另一方面,我们必须在每次访问受保护的路由时进行单独的数据库调用。 我想知道哪种方法更有效。

提前感谢您的回答:)

【问题讨论】:

  • 第一种方法可能更有效,但最大的缺点是,如果您使用第一种方法并且用户更改了他们的姓名、电子邮件等,那么您将使用不正确的信息。我总是会进行额外的数据库调用以确保您拥有正确的数据

标签: javascript node.js jwt authorization jwt-auth


【解决方案1】:

使用 ID 签署 JWT 令牌,因为在初始创建后不太可能更改。

用户名和电子邮件等其他数据很容易发生变化。

编辑:这是我不久前做的一个练习的用户注册示例。希望能给大家一些帮助。

// POST api/users => Register user
router.post("/", (req, res) => {
  const { name, email, password } = req.body;

  // Simple validation
  if (!name || !email || !password) {
    return res.status(400).json({ msg: "Please enter required information" });
  }

  // Check for existing user
  User.findOne({ email }).then((user) => {
    if (user) return res.status(400).json({ msg: "User already exists" });

    const newUser = new User({
      name,
      email,
      password,
    });

    // Create salt and Hash
    bcrypt.genSalt(10, (err, salt) => {
      bcrypt.hash(newUser.password, salt, (err, hash) => {
        if (err) throw err;
        newUser.password = hash;
        newUser.save().then((user) => {
          jwt.sign(
            { id: user.id },
            jwtSecret,
            { expiresIn: 3600 },
            (err, token) => {
              if (err) throw err;
              res.json({
                token,
                user: {
                  id: user.id,
                  name: user.name,
                  email: user.email,
                },
              });
            }
          );
        });
      });
    });
  });
});

【讨论】:

  • 您的回答很有帮助,但不是很清楚。请使用示例详细说明,以便我可以将此答案标记为已接受。谢谢@K4R1。
  • @IbadShaikh 好的,添加了一个示例。希望它提供一些见解。我不是这些事情上最好的讲师/解释者。
  • 例子中涉及到了MongoDB模型和bcrypt哈希,但是JWT部分明显存在。
【解决方案2】:

假设您有一个包含整个用户对象的有效负载,包括:

  • _id
  • 姓名
  • 电子邮件
  • 用户名

缺点案例:

  • 假设用户后来编辑了他的名字,这意味着他的数据 在数据库中得到更新,但他的有效载荷仍然过时 旧名称,因为没有进行数据库调用来获取更新的记录。

  • 如果用户现在尝试发出需要他的名字的 POST 请求 请求正文,然后将过时的名称推送到 数据库而不是他的新名字。

    app.post('/event', auth, (req, res) => {
       // creates an event with his old name.
       // Because the current payload contains old name.
    })
    
  • 现在如果用户注销然后再次登录,令牌将 在有效负载中包含用户的新名称。

  • 并且每当使用用户的新更新名称获取所有事件时 保存在有效负载中,最近创建的最新事件 不会获取旧名称,因为它包含旧名称 用户名。

根据我的知识,这是我能给出的最好的解释。 分享你的想法!

谢谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 2017-08-21
    • 2015-02-28
    相关资源
    最近更新 更多