React+Node.js+MySQL哈希密码后登录失败问题求助
登录验证失败:原始密码无法匹配哈希存储的密码问题排查与修复
兄弟,你这明显踩了个哈希顺序搞反的经典坑,再加上可能还有个函数名的小疏忽,才导致了这种诡异的现象——用原始密码登不上,直接输哈希密码反而能登,我给你一步步拆解问题和修复方案:
核心问题分析
先看你原来的login函数逻辑:
- 你先拿着用户输入的原始密码去执行SQL查询,和数据库里已经哈希过的密码做对比
- 查完之后才去哈希密码
这完全搞反了!数据库里存的是哈希后的密码,你得先把用户输入的原始密码哈希,再用哈希后的值去查数据库才行。
至于为什么用数据库里的哈希密码能登录?那是因为你直接把哈希值当密码传进去,此时SQL查询的参数就是哈希值,刚好和数据库里的存储一致,所以能匹配上——这是巧合,不是正确逻辑。
你说把哈希移到SQL之前还是不行?大概率是移的方式不对,或者还有函数名的问题(往下看)。
具体修复步骤
1. 彻底修正登录逻辑的顺序
把哈希操作提前到SQL查询之前,并且用哈希后的密码作为查询参数,修改后的auth-logic.ts代码:
async function login(credentials:CredentialsModel):Promise<string>{ const error = credentials.validate(); if(error) throw new ValidationErrorModel(error); // 第一步:先哈希用户输入的原始密码 const hashedPassword = cyber.hash(credentials.password); // 这里注意函数名!后面会说 // 第二步:用哈希后的密码去查询数据库 const sql = `SELECT * FROM users WHERE username = ? AND password = ?`; const users = await dal.execute(sql, [credentials.username, hashedPassword]); if (users.length === 0) throw new UnauthorizedErrorModel("Incorrect username or password"); const user = users[0]; const token = cyber.getNewToken(user); return token; }
2. 检查哈希函数的调用名(关键细节!)
看你给出的哈希函数定义是:
function has(plainText: string):string{ if(!plainText) return null; const hashedText = crypto.createHmac("sha512", salt).update(plainText).digest("hex"); return hashedText; }
函数名是has,但你在登录逻辑里调用的是cyber.hash——如果你的cyber模块里导出的哈希函数是has而不是hash,那这里会调用一个不存在的方法,导致哈希值错误(甚至返回undefined),这也会导致匹配失败!
赶紧检查cyber模块的导出,确保调用的函数名和定义一致:
- 如果导出的是
has,就改成cyber.has(credentials.password) - 如果要统一叫
hash,就把哈希函数的名字改成hash
3. 确认用户创建时的哈希逻辑一致
最后必须确认:你在创建用户存入数据库的时候,用的是完全相同的盐值和哈希函数!如果创建用户时用了不同的盐、不同的哈希算法,或者根本没哈希直接存了原始密码,那就算登录时哈希了也匹配不上。
验证修复
修复后:
- 用原始密码登录:系统会先哈希原始密码,再和数据库里的哈希值对比,匹配成功就能登录
- 用哈希密码登录:此时哈希后的密码会和数据库里的哈希值再次哈希,结果肯定不一样,会登录失败(这才是正确的安全逻辑)
内容的提问来源于stack exchange,提问作者DennisR93
相关产品推荐
相关产品推荐

