我希望为Bcrypt加密的密码重现Sequel的validates_min_length
错误。我无法使用验证,因为它将测试密码哈希,而不是未加密的文本。
我很难通过password=
方法来产生所需的错误。
require 'sequel'
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
def validate
super
validates_presence [:name,:password]
validates_unique [:name]
validates_min_length 8, :password
end
end
IRB:
irb(main):001:0> u=User.new(name: 'foobar', password: 'Pa55w0rd')
=> #<User @values={:name=>"foobar", :password=>"Pa55w0rd"}>
irb(main):002:0> u.valid?
=> true
irb(main):003:0> u.password=nil
=> nil
irb(main):004:0> u
=> #<User @values={:name=>"foobar", :password=>nil}>
irb(main):005:0> u.valid?
=> false
irb(main):007:0> u.errors
=> {:password=>["is not present", "is shorter than 8 characters"]}
irb(main):008:0> u.password='foo'
=> "foo"
irb(main):009:0> u
=> #<User @values={:name=>"foobar", :password=>"foo"}>
irb(main):010:0> u.valid?
=> false
irb(main):011:0> u.errors
=> {:password=>["is shorter than 8 characters"]}
require 'sequel'
require 'bcrypt'
DB = Sequel.sqlite
DB.create_table(:users) do
primary_key :id
String :name, null: false, unique: true
String :password_hash, null: false
end
class User < Sequel::Model
plugin :validation_helpers
include BCrypt
def validate
super
validates_presence [:name,:password]
validates_unique [:name]
end
def password
# check for :password_hash existence to ensure that validates_presence :password works correctly
@password ||= Password.new(password_hash) if password_hash
end
def password=(new_password)
# add validation errors
errors.add(:password, 'is shorter than 8 characters') if new_password==nil || new_password.length < 8
if new_password == nil
@password = nil
else
@password = Password.create(new_password)
end
self.password_hash = @password
end
end
IRB:
irb(main):001:0> u=User.new(name: 'foobar', password: 'Pa55w0rd')
=> #<User @values={:name=>"foobar", :password_hash=>"$2a$10$K3UALPYz/bb5bdrGmbq22eRM31A6rU3kqkbzcU4.6J5APQVSqxQo6"}>
irb(main):002:0> u.valid?
=> true
irb(main):003:0> u.password=nil
=> nil
irb(main):004:0> u
=> #<User @values={:name=>"foobar", :password_hash=>nil}>
irb(main):005:0> u.valid?
=> false
irb(main):006:0> u.errors
=> {:password=>["is not present"]}
irb(main):007:0> u.password='foo'
=> "foo"
irb(main):009:0> u
=> #<User @values={:name=>"foobar", :password_hash=>"$2a$10$lA6fsKXSvl5cd.Zl53qEqOzxk1LPehvGujWaXwcf1//IUc82CmowC"}>
irb(main):008:0> u.valid?
=> true
两个无效密码(nil
,'foo')都缺少is shorter than 8 characters
错误。
我错过了什么?
版本:
$ sequel --version
sequel 5.7.1
答案 0 :(得分:3)
@password
实际上不会短于8个字符。 BCrypt :: Password是字符串的子类,它与密码哈希的长度相同。如果您想使用验证来确保密码的大小,则必须在@password
中设置password=
。
答案 1 :(得分:0)
我不是100%确定功能,但这应该适合你。
def validate
super
validates_presence [:name,:password]
validates_unique [:name]
validates_min_length 8, :password
end
def password=(new_password)
return unless @password = new_password and @password.to_s.length >= 8
self.password_hash = Password.create(password)
end
我添加了实际长度验证以进行验证,以便valid?
将返回false。另外,我稍微清理了password=
方法。
所以现在password=
有一个保护条款,如果密码无效,只需返回&#34;少于8个字符&#34;。
否则,我们会通过Password.create
创建一个新的password_hash,并将其分配给@password_hash
。
请注意:我建议的代码与您的代码之间存在功能变化,即{&#34; new_password&#34;}时@password_hash
未被覆盖。是无效的。这对我来说似乎很直观,无效的密码可能会覆盖现有的有效password_hash,从而改变我的实现方式。
所有这一切都说明你最好的选择实际上就是用这个
class User < Sequel::Model
plugin :validation_helpers
include BCrypt
attr_accessor :password
def validate
super
validates_presence [:name,:password]
validates_unique [:name]
validates_min_length 8, :password
end
def before_save
self.password_hash = Password.create(password)
end
end
如果模型通过验证检查,这将避免所有操作并且只会创建password_hash
(这是您实际需要的所有操作)
答案 2 :(得分:0)
这可以按照需要运行:
require 'sequel'
require 'bcrypt'
DB = Sequel.sqlite
DB.create_table(:users) do
primary_key :id
String :name, null: false, unique: true
String :password_hash, null: false
end
class User < Sequel::Model
plugin :validation_helpers
include BCrypt
def validate
super
validates_presence [:name,:password]
validates_unique [:name]
errors.add(:password, 'is shorter than 8 characters') if @password==nil || @password.length < 8
end
def password
Password.new(password_hash) if password_hash
end
def password=(new_password)
# uncomment to prevent bad passwords from changing a good password; probably needs to include a non-terminating error message
# return if new_password==nil || new_password.length < 8
# store clear-text password for validation
@password = new_password
#modify password hash accordingly
self.password_hash = if new_password then Password.create(new_password) else nil end
end
end