使用Argon2加密密码存入PostgreSQL后验证失败求助
问题:Argon2加密密码存入PostgreSQL后验证失败
我用Kotlin结合Argon2实现用户密码加密并存入PostgreSQL数据库。加密和验证函数在测试阶段完全正常,但把加密后的密码存入数据库后,验证时始终返回错误。
相关代码
加密与验证函数
private val argon2 = Argon2Factory.create(Argon2Factory.Argon2Types.ARGON2id, 32, 64) fun String.encode(): String = argon2.hash(3, 64 * 1024, 1, this.toCharArray()) fun String.checkEncoding(hash: String): Boolean = argon2.verify(hash, this.toCharArray())
测试代码(验证正常)
class HashingTest : ShouldSpec({ context("Encoding a string") { should("encode correctly") { val dataOne = "S@!sc_%kah" val encondeOne = dataOne.encode() val dataTwo = "S@!sc_%kah" dataTwo.checkEncoding(encondeOne) shouldBe true // 验证通过 } } })
数据库操作代码(验证失败)
// 实体类 data class User( override val id: UUID, val username: String, val password: String, ) : IEntity // 插入数据(使用Exposed框架) private fun newUser(schema: String, entity: User) { val table = toUserTable(schema) table .insert { it[id] = entity.id it[username] = entity.username it[password] = entity.password.encode() } } // 查询并验证用户 fun findUser(schema: String, model: SignInModel): User? { val table = toUserTable(schema) val user = table .select { table.username eq model.username } .firstNotNullOfOrNull { toUser(schema, it) } val verifying = model.password.checkEncoding(user!!.password) // 此处始终返回false return when (verifying) { true -> user false -> null } }
问题原因及解决方案
1. 数据库字段长度不足
Argon2生成的hash字符串完整长度通常在90-100字符左右,如果数据库中password字段设置为VARCHAR(50)这类短长度,会导致hash被截断,验证必然失败。
解决:将数据库password字段修改为VARCHAR(255)或TEXT类型,确保能完整存储hash值。
2. 重复加密问题
检查newUser函数:如果传入的entity.password已经是加密后的hash值,再次调用encode()会导致双重加密,存入的是“hash的hash”,验证时自然匹配不上。
解决:确保传入newUser的User实体中,password是用户输入的明文密码,仅在入库前调用encode()加密。
3. 数据读取时的异常处理
检查toUser函数从数据库映射实体的逻辑,确认没有对password字段做转义、截断或其他修改操作,保证读取的hash和存入的完全一致。
4. 调试排查
在findUser中添加日志,直观对比存储的hash和验证用的hash:
fun findUser(schema: String, model: SignInModel): User? { val table = toUserTable(schema) val user = table .select { table.username eq model.username } .firstNotNullOfOrNull { toUser(schema, it) } // 打印调试信息 println("存储的Hash: ${user?.password}") println("输入的明文密码: ${model.password}") val verifying = user?.let { model.password.checkEncoding(it.password) } ?: false println("验证结果: $verifying") return if (verifying) user else null }
通过日志可以快速确认hash是否被截断或篡改。
内容的提问来源于stack exchange,提问作者Rodrigo Batista
相关产品推荐
相关产品推荐

