2012-03-27 18 views
1

私のクライアントは、すべてのユーザーデータが暗号化望んでいるので、私はGibberishを使用して特定のプロパティ暗号化するバックbefore_saveafter_findコール作成しました:before_saveを複数回実行するモデルを作成しますか?

# user.rb 
    before_save UserEncryptor.new 
    after_find UserEncryptor.new 

# user_encryptor.rb 
class UserEncryptor 
    def initialize 
    @cipher = Gibberish::AES.new("password") 
    end 

    def before_save(user) 
    user.first_name = encrypt(user.first_name) 
    user.last_name = encrypt(user.last_name) 
    user.email = encrypt(user.email) unless not user.confirmed? or user.unconfirmed_email 
    end 

    def after_find(user) 
    user.first_name = decrypt(user.first_name) 
    user.last_name = decrypt(user.last_name) 
    user.email = decrypt(user.email) unless not user.confirmed? or user.unconfirmed_email 
    end 

    private 
    def encrypt(value) 
     @cipher.enc(value) 
    end 

    def decrypt(value) 
     @cipher.dec(value) 
    end 
end 

まあ、Deviseを使用してユーザーが最初にサインアップし、モデルのルックスをそれはまさにそうすべきです。しかし、ユーザーが確認すると、ユーザーを調べると、first_namelast_nameのプロパティが複数回暗号化されているように見えます。そこで、私はbefore_saveメソッドにブレークポイントを置き、確認リンクをクリックすると、3回連続して実行されています。その結果、暗号化された値が再び暗号化され、再び暗号化され、次回にレコードを取得し、その後毎回暗号化された値が2回取得されます。

今、なぜこれが起こっているのですか?同じロジックを実行している他の非開発モデルでは発生しません。 Deviseにはcurrent_userがいくつかの場所にキャッシュされていて、それぞれの場所にユーザーを保存していますか?他にどのようにbefore_saveコールバックが3回呼び出されてbefore_findが実行されるのですか?

また、Deviseを使用しているときにユーザーデータを暗号化するにはどうすればよいですか。私もattr_encrypteddevise_aes_encryptableの問題を抱えていましたので、私はそれらの提案をたくさん得た場合、私は投稿するためにさらに質問があると思います:-)

答えて

2

私は同僚の助けを借りて私の問題を解決しました。

姓と名を暗号化するには、暗号化されているかどうかを示すフラグをモデルに追加するだけで十分でした。その方法は、複数が発生し保存した場合、モデルは、それがすでに暗号化されています知っていて、そのステップをスキップすることができます

def before_update(user) 
    unless user.encrypted 
     user.first_name = encrypt(user.first_name) 
     user.last_name = encrypt(user.last_name) 
     user.encrypted = true 
    end 
    end 

    def after_find(user) 
    if user.encrypted 
     user.first_name = decrypt(user.first_name) 
     user.last_name = decrypt(user.last_name) 
     user.encrypted = false 
    end 
    end 

メールアドレスの場合、これは十分ではなかったです。 Deviseはキャッシュされた値をリセットして本当に奇妙なことをしていたので、電子メールアドレスはまだ二重暗号化されていました。代わりにメールアドレスを暗号化するために、コールバックにフックするので、私たちは、ユーザモデルにいくつかのメソッドをオーバーライド:

def email_before_type_cast 
    super.present? ? AES.decrypt(super, KEY) : "" 
    end 

    def email 
    return "" unless self[:email] 
    @email ||= AES.decrypt(self[:email], KEY) 
    end 

    def email=(provided_email) 
    self[:email] = encrypted_email(provided_email) 
    @email = provided_email 
    end 

    def self.find_for_authentication(conditions={}) 
    conditions[:email] = encrypted_email(conditions[:email]) 
    super 
    end 

    def self.find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) 
    attributes[:email] = encrypted_email(attributes[:email]) if attributes[:email] 
    super 
    end 

    def self.encrypted_email decrypted_email 
    AES.encrypt(decrypted_email, KEY, {:iv => IV}) 
    end 

これは私たちが道のほとんどを得ました。しかし、私のDeviseモデルは再確認可能なので、ユーザーの電子メールアドレスを変更して保存しようとすると、再確認可能なモジュールに何か不安があり、レコードが100回程度保存された後、スタックオーバーフローとロールバックが発生します。これで、すべて私たちの個人情報の暗号化されている

def email_was 
    super.present? ? AES.decrypt(super, KEY) : "" 
    end 

:私たちは、トリックを行うためのユーザモデルのもう一つのメソッドをオーバーライドするために必要なことがわかりました!わーい!

関連する問題