bcrypt.comparehashandpassword报“not the hash of the given password”错误,主因是首参非合法哈希:明文误作哈希、哈希被截断(字段不足60字符)、空值或格式损坏;须确保数据库存的是完整60字符bcrypt哈希字符串,且调用时首参为该哈希、次参为明文密码。

别用“加密”这个词——bcrypt 是不可逆哈希,不是加密。直接调用 bcrypt.GenerateFromPassword 和 bcrypt.CompareHashAndPassword 就对了,但参数类型、顺序、存储方式错一个,登录必挂。
为什么 bcrypt.CompareHashAndPassword 总报 “not the hash of the given password”
这个错误不是密码输错了,而是你传给它的第一个参数根本不是合法的 bcrypt 哈希字符串。
- 最常见:传进去的是明文密码(比如把
u.Password当成明文去比对,而它本该是哈希) - 其次常见:数据库字段太短(
VARCHAR(50)),60 字节的哈希被截断成 50 字符,CompareHashAndPassword一读就发现长度不对、前缀缺失,立刻报错 - 还有就是空值:查用户没查到,
u.Password是空字符串,或入库前没校验,存了个""进去 - 调试时可用
fmt.Println(len(u.Password))快速确认——正常必须是 60
bcrypt.GenerateFromPassword 的 cost 参数怎么设才不翻车
cost 不是越大越安全,是平衡点。设错会导致要么被爆破,要么接口卡死。
- 硬编码
10太弱,现代 GPU 几秒能跑千万次;设成20单次哈希可能超 1.5 秒,高并发下 goroutine 积压 - 生产环境推荐从
12起步(约 150–250ms),压测看 P95 延迟是否可控 - 配置项读出后必须校验:
if cost bcrypt.MaxCost,否则直接 panic - 测试环境可用
4加速,但绝不能和生产共用同一份配置
哈希值存进数据库前必须做三件事
存错格式 = 后续所有验证都失效,且问题难定位。
- 必须转成
string再存:hashedStr := string(hashed),别存[]byte二进制 - 数据库字段至少
VARCHAR(255)(MySQL)或TEXT(PostgreSQL),VARCHAR(60)是底线,但留余量更稳妥 - 入库前确保无空格:
strings.TrimSpace(password)校验长度后立即做,避免前端带空格提交 - 额外建议:模型层加 GORM tag
gorm:"size:255;not null",并用正则预检哈希格式:^\$2[abxy]\$\d{2}\$.{53}$
CompareHashAndPassword 的参数顺序和空密码陷阱
顺序颠倒不是逻辑错,是直接触发校验失败——函数内部会先解析第一个参数是否为有效哈希,不是就报错。
- 正确顺序:
bcrypt.CompareHashAndPassword([]byte(storedHash), []byte(plainPassword)) - 绝对禁止在登录流程里再调一次
GenerateFromPassword——那生成的是新哈希,跟库里存的老哈希永远不等 - 空密码不校验会埋雷:某些旧实现对
""返回 nil,看似“通过”,实则绕过认证;务必前置判空:if len(plainPassword) == 0 - 错误处理要分层:
err == bcrypt.ErrMismatch是密码错,其他 error(如哈希格式异常)应记日志并拒之,不进业务逻辑
真正容易被忽略的是:哈希值一旦入库,就再也不能当字符串随意 Trim 或 Replace;哪怕只是日志打印前多调了一次 strings.ReplaceAll,也可能破坏 $ 分隔结构。所有中间操作,必须以「原样进出」为第一原则。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











