我需要在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)
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"]相同.
归档时间: |
|
查看次数: |
42867 次 |
最近记录: |