将 ObjectID 与 jwt.sign() 和 verify() 一起使用

Posted

技术标签:

【中文标题】将 ObjectID 与 jwt.sign() 和 verify() 一起使用【英文标题】:Using ObjectID with jwt.sign() and verify() 【发布时间】:2018-01-13 01:12:53 【问题描述】:

登录我的系统后,我通过jsonwebtoken的sign方法运行登录用户的MongoDB_id。它返回给我一个哈希值,然后我将它放入客户端向我的服务器发出的每个后续请求的会话标头中。

我现在想解码会话并从标头中恢复字符串 _id,因此我针对 jsonwebtoken 的 verify 方法运行它。我这样做不是为了进行身份验证(已经通过在数据库中查找会话来处理)。我正在恢复_id,以便将用户的活动记录在单独的集合中。我通过中间件运行verify函数并将解码结果保存在req.decoded中。

但是,当我登录req.decoded 时,它是一个 BSON 对象,而不是一个字符串:

 _bsontype: 'ObjectID',
  id:
    type: 'Buffer',
     data: [ 89, 128, 145, 134, 118, 9, 216, 20, 175, 174, 247, 33 ] ,
  iat: 1501903389,
  exp: 1501989789 

如何从该对象中恢复_id 值,以便我可以在我的集合中再次查找该记录?

我尝试过的

我尝试了以下方法,但没有成功:

model.find(req.decoded).then() 给我这个错误:

错误:对象 [req.decoded 的内容] 不是有效的 ObjectId

model.find(_id: req.decoded) 给我这个错误:

CastError: Cast to ObjectId failed for value [contents of req.decoded here] at path "_id" for model [model here]

req.decoded.toString()日志[object Object]

JSON.stringify(req.decoded) 只是将 BSON 变成一个字符串

【问题讨论】:

【参考方案1】:

这当然取决于您首先将数据实际提供给.sign() 的方式,这与通过提供值简单地提供ObjectID 的“对象”不同而是。

这实际上在general usage for .sign() 中被覆盖为:

如果有效载荷不是缓冲区或字符串,它将使用 JSON.stringify 强制转换为字符串。

所以简而言之,该版本将“字符串化”对象形式,需要一些“挖掘”。在您的表单中,解码后的对象具有id 的属性和data 的子属性,其中包含可以转换为Buffer 的字节数组。这就是你要做的:

  let newId = Buffer.from(req.decoded.id.data).toString('hex');

然后newId 将是由字节的'hex' 编码值表示的“字符串”。当在任何“查询”或“更新”中发出匹配_id 的架构时,猫鼬当然会将其翻译成ObjectId

当然,“替代方案”首先是使用 ObjectId 中的 .toString() 值简单地替换为 .sign()。然后.verify() 的结果将只是提供的“十六进制字符串”,而不是ObjectID 本身的JSON.stringify 结果。

通过列表进行演示:

const bson = require('bson'),
      jwt = require('jsonwebtoken');

// Stored ObjectID
console.log("Round 1");
(function() 
  let id = new bson.ObjectID();
  console.log("Created: %s", id);

  let token = jwt.sign(id,'shhh');                // Supply value as ObjectID
  let decoded = jwt.verify(token,'shhh');

  console.log("Interim");
  console.log(decoded);

  let newId = Buffer.from(decoded.id.data).toString('hex');
  console.log("Decoded: %s", newId);
)();

console.log("\nRound 2");
// Stored String value
(function() 

  let id = new bson.ObjectID();
  console.log("Created: %s", id);

  let token = jwt.sign(id.toString(), 'shhh');    // Supply value as string
  let decoded = jwt.verify(token,'shhh');

  console.log("Decoded: %s", decoded);

)();

给出输出,显示输入值和解码值:

Round 1
Created: 59857328090c497ce787d087
Interim
 _bsontype: 'ObjectID',
  id:
    type: 'Buffer',
     data: [ 89, 133, 115, 40, 9, 12, 73, 124, 231, 135, 208, 135 ] ,
  iat: 1501917992 
Decoded: 59857328090c497ce787d087

Round 2
Created: 59857328090c497ce787d088
Decoded: 59857328090c497ce787d088

并演示了将值提供给.sign() 的两种用法以及随后的.verify() 调用的结果。

【讨论】:

以上是关于将 ObjectID 与 jwt.sign() 和 verify() 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

放置jwt.sign代码时出现JWT错误

如何在 jwt.sign 中将 IP 地址作为参数

jwt sign(我需要获得令牌,但我得到了未定义)

koa2 中 koa-jwt 的使用

如何解决未处理的拒绝 TypeError: Converting circular structure to JSON for jwt.sign

jsonwebtoken.sign() 失败并设置了 expiresIn 选项