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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 17:50:23