2011-07-28 24 views
3

私はすでに多くのコードが用意されているプロジェクトに取り掛かりました。 Ruby on Railアプリケーションで、Deviseをユーザ認証に使用します。アプリケーションの要件の1つは、ユーザーがパスワードを変更したときに、以前に使用した最後の3つのパスワードと同じパスワードを使用できないことです。これを実現するために、特定のユーザーのパスワードの履歴を含む表があります。これらのパスワードは、ユーザーがパスワードを変更する前に存在していた暗号化されたパスワードのコピーです。保存された暗号化されたパスワードと一致するようにパスワードを暗号化します。

ここで問題が発生します。特定のユーザーの新しいパスワードを収集するパスワード変更フォームがあります。新しいパスワードの暗号化された値と履歴の古いパスワードの暗号化された値を照合できるように、新しいパスワードを取得して暗号化できるようにする必要があります。工夫と標準bcryptのを使用して

技術的なもの
Railsのバージョン3.0.9
工夫バージョン1.3.4
。 bcrypt_rubyバージョン2.1.4

これを行うには、Deviseでサポートされているreset_passwordメソッドをオーバーライドします。これにより、独自のメソッドhas_repeated_pa​​sswordをユーザコントローラに導入することができます。

私が始めたhas_repeated_pa​​sswordのバージョンは以下の通りです:

def has_repeated_password? 
    return false if self.new_record? || self.version == 1 
    histories = self.versions.find(:all, :order => 'version DESC', :limit => 3) 

    histories.detect do |history| 
     history.encrypted_password == self.class.encryptor_class.digest(self.password, self.class.stretches, history.password_salt, self.class.pepper) 
    end 
    end 

ここでの問題は、エラーにこのルーチンが実行するたびに引き起こして、暗号化クラスが定義されないことです。これが主張する多くの例があるにもかかわらず、Deviseがデフォルトの暗号化を使用しているときに動作するようにはできません。この時

第二の試みは、次のコードである。この場合

def has_repeated_password?<br> 
    return false if self.new_record? || self.version == 1 
    histories = self.versions.find(:all, :order => 'version DESC', :limit => 3) 

    histories.detect do |history| 
     pwd = self.password_digest(self.password) 
     history.encrypted_password == pwd 
    end 
    end 

、私は、データベース内のパスワードがあることを確認しているにもかかわらず、保存されたパスワードのいずれかに一致するパスワードを取得することはありません私が期待しているもの。

私はそこで見つけられるものを見るためにDeviseコードを掘り下げようとしています。私は、autenticationは、保存されたパスワードとユーザーから収集したパスワードを一致させるときに何らかの形でこれを行う必要があることを知っています。

ご協力いただければ幸いです。

答えて

2

私は自分の問題に対する解決策を見つけたと思う。これの重要なポイントは、ユーザーモデルの一部ではない暗号化されたパスワードを取得しようとしていたことです(これ以上のものはDeviseと結びついています)。この解決策は、Deviseが標準の暗号化ツールとしてBcryptを使用することを前提としています(Deviseのどのバージョンが動いたかは覚えていません)。 Bcrypt/Deviseは、暗号化されたパスワードに実際にパスワードの塩を埋め込みます。あなたが塩とコショウを持っているなら、あなたは同じ暗号化された値を生成するために同じパスワードを得ることができます。

def has_repeated_password? 
    return false if self.new_record? || self.version == 1 

    histories = self.versions.find(:all, :order => 'version DESC', :limit => 3) 
    histories.detect do |history| 
     bcrypt = ::BCrypt::Password.new(history.encrypted_password) 
     password = ::BCrypt::Engine.hash_secret("#{self.password}#{self.class.pepper}", bcrypt.salt) 
     password == history.encrypted_password 
    end 
    end 

ここで重要なのは、Bcyrptオブジェクトは元のパスワードを生成した同じ塩を使用して、既存の暗号化されたパスワードを使用して作成しなければならないことである。だからここ

は、上記referncedルーチンの更新されたコードです。これは私の保存された歴史的な暗号化されたパスワード(history.encrypted_pa​​ssword)を与えることによって達成されます。他の重要な要素の1つは、履歴パスワードと提案された新しいパスワードの両方がDeviseによって管理される同じペッパーを使用することです。したがって、Engneを使用します。意図した新しいパスワードでhas_secretを呼び出すと、履歴パスワードと比較することができます。

Deviseがサポートしているすべてのパスワードメソッドは、現在のユーザーオブジェクトのユーザーパスワードを使用すると仮定しているため、bcryptコードをここに移動する必要がありました。

+0

'p = BCrypt :: Password.new(history.encrypted_pa​​ssword)'と 'p == password'を使う方が正しいです。 'BCrypt :: Password'クラスには' == '演算子が定義されています。 –

関連する問題