代码之家  ›  专栏  ›  技术社区  ›  Ethan

如何使setter方法在ActiveRecord中设置数据之前对其进行加密?

  •  2
  • Ethan  · 技术社区  · 15 年前

    我想安装一个轨道 User 具有数据库列的模型 password . 我想这样当我打电话的时候…

    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
    

    但有个错误说 密码= 不存在。

    4 回复  |  直到 15 年前
        1
  •  8
  •   Matt Rogish    15 年前

    仅供参考,您可能希望签出restful_身份验证插件,因为它将为您执行此操作。为什么要自己滚?

    作为“认证”的方式是:

    1. 数据库/模型有一个名为“加密密码”的列
    2. 创建名为password的虚拟属性
    3. 在查找(..)中不填充密码,因此如果密码为空,则不加密
    4. 如果密码不为空,这意味着用户输入了一个密码,那么继续加密并用加密的密码填充

    代码截图(从我的用户类随机复制粘贴,因此不要盲目粘贴此内容):

    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
    
        2
  •  1
  •   nitecoder    15 年前

    对于Ethan的评论,什么是虚拟属性,虚拟属性是不在数据库中的属性,就像Matt的attr_accessor:password,通过这种方式,您可以接受来自用户的输入,但不必以那种形式存储,在这种情况下,我们希望能够接受明文密码,但我们希望将其加密存储。为此,我们有一个虚拟属性:password,在数据库中,我们将其存储为加密的\密码。

        3
  •  1
  •   Ryan Bigg Andrés Bonilla    15 年前

    好吧,你可以重写setter:

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

    而这将 总是 加密值。你不需要在保存之前 一个属性访问器。

        4
  •  1
  •   Jonas Kölker    15 年前

    请注意,最好为每个用户选择一个随机的n位值(在创建该用户时),并在散列密码时将其预先发送给密码。

    原因是:如果任何人获得了你的数据库,他们不仅不能立即看到用户的密码,他们也看不到两个用户是否有相同的密码(如果其中一个用户获取了你的数据库,这一点很重要),并且某种类型的哈希破解攻击(彩虹表)变得更加困难。