我的客户希望加密所有用户数据,因此我创建了一个before_save
和after_find
回调,它将使用Gibberish
加密某些属性:
# 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_name
和last_name
属性看起来已经多次加密。所以我在before_save
方法中放了一个断点,然后点击确认链接,我发现它连续执行了三次。结果是加密值再次加密,然后再次加密,因此下次我们检索记录时,每次我们获得两次加密值。
现在,为什么会发生这种情况?对于执行相同逻辑的其他非设计模型,不会发生这种情况。 Devise
是否将current_user
缓存在几个不同的位置,并将用户保存在每个位置?如果在执行下一个before_save
之前调用before_find
回调3次怎么办?
更重要的是,当我使用Devise
时,如何成功加密用户数据?我也遇到了attr_encrypted
和devise_aes_encryptable
的问题,所以如果我得到很多这些建议,那么我想我还有一些问题需要发布: - )
答案 0 :(得分: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
现在我们所有的个人身份信息都已加密!耶!