2012-03-27 53 views
1

我的客戶希望所有的用戶數據進行加密的,所以我創建使用before_saveafter_find回調,將加密某些屬性Gibberish:當用戶第一次簽約使用Devise,該模型看起來設計多次運行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 

好,關於它應該。但是,一旦用戶確認,如果我檢查用戶,first_namelast_name屬性看起來已被多次加密。因此,我在before_save方法中放置了一個斷點並單擊確認鏈接,我發現它已連續執行三次。結果是加密的值再次被加密,然後再次加密,所以下次我們檢索記錄時,每次都會得到兩次加密的值。

現在,爲什麼會發生這種情況?對於執行相同邏輯的其他非設計模型而言,這種情況不會發生。 Devise是否將current_user緩存在幾個不同的位置,並將用戶保存在每個位置?在執行下一個before_find之前,還有什麼可以調用before_save回調3次?

而且,更重要的是,當我使用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模型是可重新定義的,所以當我更改用戶的電子郵件地址並嘗試保存時,可再次確認的模塊遇到了一些奇怪的事情,記錄被保存了大約一百次,然後出現堆棧溢出和回滾。我們發現,我們需要覆蓋的用戶模型多了一個方法,這樣的伎倆:

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

我們的個人身份信息,現在都被加密!好極了!