You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用bcrypt哈希日期后验证始终失败的原因是什么?

问题:bcrypt生成的token验证始终不匹配

我用bcrypt基于用户的joinDate生成token并发送到邮箱,代码如下:

const token = await bcrypt.hash(joinDate, 10);

用户点击邮件链接后,后端从请求参数中获取token,链接格式为:
/api/unsubscribe?userId="abcd"&token="token_that_was_generated_using_bcrypt_and_sent_to_user"

后端获取参数的代码:

const {userId, token} = req.query;

验证时,我把数据库取出的joinDate转为字符串后和token对比,但始终返回false:

const joinDate = user.joinDate.toString();
const tokenValidated = await bcrypt.compare(joinDate, token)//this is always false although us generated from same joinDate field

明明用的是同一个joinDate字段,为什么验证一直不通过?


原因及解决方案

1. URL参数的引号导致token值被篡改

你生成的链接里,userId和token都带了双引号(比如token="xxx"),后端通过req.query获取到的token会包含这些双引号,而你生成token时是用纯joinDate哈希的,没有引号,自然匹配不上。

解决方法:生成链接时去掉参数值的双引号,正确的链接格式应该是:
/api/unsubscribe?userId=abcd&token=token_that_was_generated_using_bcrypt_and_sent_to_user

2. Date对象序列化格式不一致

生成token时如果直接用Date对象joinDate传入bcrypt.hash,bcrypt会自动把它转成字符串,但这个字符串格式可能和你验证时调用toString()得到的格式不一样(比如时区差异、字符串细节不同)。比如:

  • 生成时:joinDate作为Date对象,bcrypt内部转的字符串可能是"Wed Sep 18 2024 12:34:56 GMT+0800 (中国标准时间)"
  • 验证时:从数据库取出的user.joinDate转toString()可能因为数据库存储的时区或序列化方式不同,得到的字符串有细微差异,导致哈希对比失败。

解决方法:生成token和验证时,统一使用固定格式的字符串,比如ISO标准格式:

// 生成token时
const joinDateStr = joinDate.toISOString();
const token = await bcrypt.hash(joinDateStr, 10);

// 验证时
const joinDateStr = user.joinDate.toISOString();
const tokenValidated = await bcrypt.compare(joinDateStr, token);

3. 数据库存储的joinDate精度问题

如果数据库存储的joinDate和生成token时的joinDate精度不一致(比如生成时是毫秒级,数据库存成了秒级),转成字符串后也会有差异,导致对比失败。

解决方法:确保数据库存储的joinDate和生成token时的时间精度完全一致,验证时也用相同精度的字符串进行对比。


内容的提问来源于stack exchange,提问作者Kal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:50:26