web-dev-qa-db-fra.com

Concevoir: crypter manuellement le mot de passe et stocker directement

J'essaie de migrer une tonne d'utilisateurs d'une ancienne base de données. Pour ce faire, j'utilise activerecord-import et j'essaie de sauvegarder toutes mes données utilisateur directement dans DB (en contournant le modèle utilisateur).

Mon problème: je dois prendre le mot de passe en texte brut de l'ancien utilisateur, le chiffrer et le stocker directement dans la base de données. Je sais comment générer un mot de passe à l'aide de Devise, mais je me demande s'il existe un moyen d'obtenir un mot de passe haché que je puisse stocker directement dans la base de données.

En espérant faire:

new_hashed_password = Devise.awesome_encrypting_method(old_user.password)

Enregistrez ensuite "new_hashed_password" directement dans la base de données sans passer par le modèle. J'ai fouillé dans Devise et j'ai trouvé ceci:

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

@@ s'étire par défaut à 10 (lib/devise.rb: 71) et n'est pas remplacé par mon initialiseur

@@ pepper par défaut à nil (lib/devise.rb: 148) et n'est pas remplacé par mon initialiseur

Je pensais pouvoir recréer manuellement password_digest () mais je pense que je manque quelque chose de fondamental à propos de Bcrypt car même avec la définition du mot de passe et des étirements, le hachage résultant est différent à chaque fois.

Des idées? Merci de votre aide!

32
jmccartie

De bonnes nouvelles et de mauvaises nouvelles.

Bonnes nouvelles:

Les opérations suivantes permettent de créer manuellement le mot de passe de votre utilisateur.

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

Vous pouvez trouver votre poivre et son coût dans votre initialiseur de devise. Cette méthode a été confirmée à l'aide de "valid_password?" De Devise méthode.

Mauvaises nouvelles:

La raison pour laquelle j'essayais d'éviter "User.new (mot de passe: mot de passe) .encrypted_password" était due à la vitesse. C'est terriblement lent. Avec toutes mes autres pièces de ma tâche d'importation, j'ai intentionnellement évité cela.

Mais il s'avère que le coût principal ici n'est pas l'instanciation d'un objet utilisateur - mais BCrypt lui-même. Il y a très peu d'augmentation notable de la vitesse lors de l'utilisation directe de BCrypt car il est intentionnellement conçu pour être lent.

Ma réponse finale: sucer, exécuter le script de râteau, aller chercher une boisson.

19
jmccartie

Vous devez le faire comme ceci:

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

C'est beaucoup mieux que d'utiliser BCrypt directement car il résume la façon dont les mots de passe sont générés à partir de votre code, ce qui le rend plus facile à comprendre et également à l'abri des changements dans la façon dont le concept construit des mots de passe cryptés. Votre code ne devrait pas et n'a aucune raison de savoir quoi que ce soit à ce sujet.

58
Robert Kajic

Aucune des autres réponses ci-dessus n'a fonctionné pour moi, alors voici ce que j'ai fait:

user.valid_password?(plain_password)

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

3
user645579

Une autre méthode est la suivante: User.new.send(:password_digest, 'xxx')

2
Paul Odeon

En supposant que vous avez une base de données mysql avec une table "utilisateurs" et une colonne "mot de passe" Et une classe de modèle ActiveRecord appelée "utilisateur" qui est connectée pour concevoir

Créez une classe de modèle ActiveRecord dans votre application app/models/old_user.rb

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

puis créez une tâche de râteau: app/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

Modifiez si nécessaire (assurez-vous que vous enregistrez les attributs utilisateur spécifiques à l'application)

Alors$ rake migrate_users

1
jacobsimeon