2009-02-16 50 views
2

我想實現一個Rails User模型,該模型有一個名爲password的DB列。我想使它這樣,當我打電話......如何在設置ActiveRecord之前讓setter方法加密數據?

user_instance.password = 'cleartext' 

的方法,像這樣把它放在實例之前散列明文:

Digest::SHA1.hexdigest(cleartext) 

我用回調試過,但問題在於,每次保存用戶時都會浪費pw,即使pw未更新也是如此。所以它會一遍又一遍地散佈並重新渲染。

我試圖重新定義password=方法...

alias password= old_password= 
def password=(cleartext) 
    old_password=(Digest::SHA1.hexdigest(cleartext)) 
end 

,但得到一個錯誤說password=不存在。

回答

8

僅供參考,您可能想查看restful_authentication插件,因爲它會爲您執行此操作。爲什麼要推出自己的?

acts_as_authenticated的方式做的:

  1. 數據庫/模型有一個名爲「encrypted_pa​​ssword」
  2. 列創建一個名爲密碼
  3. 密碼不填充上找到虛擬屬性(..)所以如果密碼爲空,請勿加密
  4. 如果密碼不是空白,表示用戶輸入了密碼,請繼續進行加密並填入encrypted_pa​​ssword

代碼剪斷(從我的用戶類隨機複製粘貼,所以不要盲目地貼上此在):

require 'digest/sha1' 
class User < ActiveRecord::Base 

    # stuff 

    # callback 
    before_save :encrypt_password 
    attr_accessor :password 

    # methods 
    def encrypt_password 
     return if password.blank? 
     salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record? 
     crypted_password = Digest::SHA1.hexdigest("--#{salt}--#{self.password}--") 
    end 
+0

什麼是「虛擬屬性」? – Ethan 2009-02-16 21:13:23

1

針對Ethan的評論,什麼是虛擬屬性,虛擬屬性是一個不在數據庫中,就像Matt的attr_accessor:password一樣,您可以接受來自用戶的輸入,但不一定以該形式存儲它,在這種情況下,我們希望能夠接受明文密碼,但我們希望將其加密存儲。要做到這一點,我們有一個虛擬屬性:密碼,並在數據庫中我們將其存儲爲encrypted_pa​​ssword。

1

嗯,你可以覆蓋setter方法:

def password=(value) 
    self[:password] = Digest::SHA1.hexdigest(value) 
end 

,這將總是加密值。您不需要before_save attr_accessor。

1

請注意,爲每個用戶選擇一個隨機的n位值(創建該用戶時)可能是一個好主意,並且在對其進行散列時將其作爲密碼的前綴。

原因是:如果有人拿到你的數據庫,他們不僅不能立即看到用戶的密碼,而且他們也看不到兩個用戶是否有相同的密碼(如果其中一個用戶獲得了密碼你的數據庫)以及某種散列破解攻擊(彩虹表)變得更加困難。

相關問題