在Ruby中创建数字,字符串,数组或散列的md5哈希

Tel*_*Sam 40 ruby md5 digest

我需要在Ruby中为变量创建一个签名字符串,其中变量可以是数字,字符串,散列或数组.散列值和数组元素也可以是这些类型中的任何一种.

此字符串将用于比较数据库中的值(在本例中为Mongo).

我的第一个想法是创建一个JSON编码值的MD5哈希,如下所示:( body是上面提到的变量)

def createsig(body)    
  Digest::MD5.hexdigest(JSON.generate(body))
end
Run Code Online (Sandbox Code Playgroud)

这几乎可以工作,但JSON.generate不会每次以相同的顺序对哈希的键进行编码,因此createsig({:a=>'a',:b=>'b'})并不总是相等createsig({:b=>'b',:a=>'a'}).

创建符合此需求的签名字符串的最佳方法是什么?

注意:对于我们之间的细节,我知道你不能JSON.generate()是数字或字符串.在这些情况下,我只是MD5.hexdigest()直接打电话.

Luk*_*uke 31

我很快编写了以下代码,没有时间在工作中对它进行真正的测试,但它应该完成这项工作.如果您发现任何问题,请告诉我,我会看看.

这应该适当地展平并对数组和散列进行排序,并且你需要有一些非常奇怪的字符串才能有任何碰撞.

def createsig(body)
  Digest::MD5.hexdigest( sigflat body )
end

def sigflat(body)
  if body.class == Hash
    arr = []
    body.each do |key, value|
      arr << "#{sigflat key}=>#{sigflat value}"
    end
    body = arr
  end
  if body.class == Array
    str = ''
    body.map! do |value|
      sigflat value
    end.sort!.each do |value|
      str << value
    end
  end
  if body.class != String
    body = body.to_s << body.class.to_s
  end
  body
end

> sigflat({:a => {:b => 'b', :c => 'c'}, :d => 'd'}) == sigflat({:d => 'd', :a => {:c => 'c', :b => 'b'}})
=> true
Run Code Online (Sandbox Code Playgroud)

  • 警告:这会改变原始对象图 (3认同)

Way*_*rad 13

如果你只能获得一个字符串表示,body并且没有Ruby 1.8哈希从一次到另一个不同的顺序返回,你可以可靠地散列该字符串表示.让我们的手弄脏一些猴子补丁:

require 'digest/md5'

class Object
  def md5key
    to_s
  end
end

class Array
  def md5key
    map(&:md5key).join
  end
end

class Hash
  def md5key
    sort.map(&:md5key).join
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,任何对象(问题中提到的类型)都会md5key通过返回用于创建校验和的可靠密钥来响应,因此:

def createsig(o)
  Digest::MD5.hexdigest(o.md5key)
end
Run Code Online (Sandbox Code Playgroud)

例:

body = [
  {
    'bar' => [
      345,
      "baz",
    ],
    'qux' => 7,
  },
  "foo",
  123,
]
p body.md5key        # => "bar345bazqux7foo123"
p createsig(body)    # => "3a92036374de88118faf19483fe2572e"
Run Code Online (Sandbox Code Playgroud)

注意:此哈希表示不对结构进行编码,仅对值的串联进行编码.因此["a","b","c"]将与["abc"]相同.