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

如何复现Sequel框架中Bcrypt加密密码的validates_min_length验证错误

解决Sequel中Bcrypt密码的最小长度验证问题

我完全懂你遇到的麻烦——Sequel的validates_min_length默认直接校验数据库字段的值,但Bcrypt加密后的密码哈希长度远超你要限制的明文长度,直接用它验证:password字段根本达不到预期效果。而且通过password=赋值时,明文会被立刻加密,也没法抓明文来做验证。下面给你两个实用的解决方案:

方案1:用虚拟属性分离明文与哈希(推荐)

这个方法逻辑最清晰,通过一个虚拟属性接收明文密码,专门对它做长度验证,再在保存前加密存入数据库字段。

require 'sequel'
require 'bcrypt'

DB = Sequel.sqlite
DB.create_table(:users) do
  primary_key :id
  String :name, null: false, unique: true
  String :password, null: false
end

class User < Sequel::Model
  plugin :validation_helpers
  include BCrypt

  # 定义虚拟属性,专门接收前端传入的明文密码
  attr_accessor :password_plain

  def validate
    super
    # 只对明文密码做最小长度验证
    validates_min_length 6, :password_plain, 
      message: "密码长度不能少于6个字符"
  end

  # 保存前把明文加密后赋值给数据库的password字段
  before_save do
    if password_plain.present?
      self.password = Password.create(password_plain)
    end
  end
end

# 测试验证效果
user = User.new(name: "craig", password_plain: "short")
user.valid? # 返回 false
puts user.errors.full_messages # 输出: ["密码长度不能少于6个字符"]

user.password_plain = "longenough123"
user.valid? # 返回 true
user.save # 成功保存,password字段存储的是加密后的哈希

方案2:重写password=方法缓存明文

如果你不想加额外的虚拟属性,可以重写赋值方法,把明文临时缓存下来,在验证时用缓存的值做校验。

class User < Sequel::Model
  plugin :validation_helpers
  include BCrypt

  # 临时存储明文密码,用于验证
  attr_reader :raw_password

  def password=(value)
    # 只有当传入的是明文(不是已加密的BCrypt::Password实例)时才缓存
    @raw_password = value unless value.is_a?(Password)
    # 调用父类方法完成加密赋值
    super(Password.create(value))
  end

  def validate
    super
    # 仅当有新的明文密码时才做长度验证
    if @raw_password.present?
      validates_min_length 6, :raw_password,
        message: "密码长度不能少于6个字符"
    end
  end
end

# 测试
user = User.new(name: "craig", password: "12345")
user.valid? # false
puts user.errors.full_messages # 输出: ["raw_password 密码长度不能少于6个字符"]

user.password = "123456"
user.valid? # true
user.save # 成功保存

注意事项

  • 如果是更新用户密码的场景,要注意:如果用户没有输入新密码(即password_plain或raw_password为空),不要触发长度验证,上面的代码已经通过present?判断处理了这个情况。
  • 方案1的虚拟属性方式更易维护,因为它明确区分了“用户输入的明文”和“数据库存储的哈希”两个概念,后续扩展其他验证(比如密码复杂度)也更方便。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:04:38