设计:手动加密密码并直接存储

问题描述 投票:0回答:6

我正在尝试从旧数据库迁移大量用户。为此,我使用 activerecord-import 并尝试将所有用户数据直接保存到数据库(绕过用户模型)。

我的问题:我需要获取旧用户的明文密码,对其进行加密,然后直接存储到数据库中。我知道如何使用 Devise 生成密码,但我想知道是否有办法获得可以直接存储到数据库的哈希密码。

希望做到:

new_hashed_password = Devise.awesome_encrypting_method(old_user.password)

然后将“new_hashed_password”直接存储到数据库中,而不经过模型。我在 Devise 中挖掘并发现了这个:

def password_digest(password)
  ::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
end

@@stretches 默认为 10 (lib/devise.rb:71) 并且不会被我的初始化程序覆盖

@@pepper 默认为 nil (lib/devise.rb:148) 并且不会被我的初始化器覆盖

我以为我可以手动重新创建password_digest(),但我认为我错过了一些关于Bcrypt的基本知识,因为即使设置密码和延伸,生成的哈希值每次都是不同的。

有什么想法吗?感谢您的帮助!

ruby-on-rails devise
6个回答
75
投票

你应该这样做:

password = 'the secret password'
new_hashed_password = User.new(:password => password).encrypted_password

这比直接使用 BCrypt 好得多,因为它抽象了代码中生成密码的方式,使其更易于理解,并且不受设计构造加密密码方式变化的影响。你的代码不应该,也没有理由知道任何事情。


19
投票

好消息和坏消息。

好消息:

以下方法可以手动创建用户的密码。

 pepper = nil
 cost = 10
 encrypted_password = ::BCrypt::Password.create("#{password}#{pepper}", :cost => cost).to_s

您可以在设备初始化程序中找到您的胡椒和成本。使用 Devise 的“valid_password?”确认了该方法。方法。

坏消息:

我试图避免“User.new(password:password).encrypted_password”的全部原因是因为速度。速度非常慢。在我的所有其他导入任务中,我都故意避免了这一点。

但事实证明,这里的主要成本不是实例化 User 对象,而是 BCrypt 本身。直接使用 BCrypt 时几乎没有明显的速度提升,因为它故意设计得很慢。

我的最终答案:忍住,运行 rake 脚本,去找饮料。


7
投票

上面的其他答案都不适合我,所以这就是我所做的:

user.valid_password?(plain_password)

https://github.com/plataformatec/devise/blob/d293e00ef5f431129108c1cbebe942b32e6ba616/lib/devise/models/database_authenticatable.rb#L44


4
投票

另一种方法是:

User.new.send(:password_digest, 'xxx')


1
投票

假设您有一个带有“用户”表和“密码”列的 mysql 数据库 还有一个名为“user”的 ActiveRecord 模型类,它连接到 devise

在您的应用程序中创建 ActiveRecord 模型类 应用程序/模型/old_user.rb

OldUser < ActiveRecord::Base
  set_table :users
  establish_connection :database => "old_database", :user => "old user", :adapter => "mysql"
end

然后创建一个 rake 任务: 应用程序/lib/tasks/migrate_users.rake

task :migrate_users => :environment do
  OldUser.find_each do |old_user|
    u = User.new(:email => old_user.email, :password => old_user.password, :password_confirmation => old_user.password);
    #if your using confirmation
    u.skip_confirmation!
    u.save!
  end
end

根据需要进行修改(确保保存任何特定于应用程序的用户属性)

然后

$ rake migrate_users


0
投票

使用设备加密器。它检查班级中是否已经设置了

pepper
。 参考:https://www.rubydoc.info/github/plataformatec/devise/Devise/Encryptor

user = User.last

encrypted_password = Devise::Encryptor.digest(user.class, 'somePass'])

user.update(encrypted_password: encrypted_password)

验证

user.valid_password?('somePass')
=> 正确

© www.soinside.com 2019 - 2024. All rights reserved.