我需要在 Ruby 中为变量创建签名字符串,其中变量可以是数字、字符串、哈希值或数组。哈希值和数组元素也可以是这些类型中的任何一种。
该字符串将用于比较数据库(在本例中为 Mongo)中的值。
我的第一个想法是创建 JSON 编码值的 MD5 哈希,如下所示:(body 是上面提到的变量)
def createsig(body)
Digest::MD5.hexdigest(JSON.generate(body))
end
这几乎可以工作,但是 JSON.generate 不会每次都以相同的顺序对哈希的键进行编码,所以 createsig({:a=>'a',:b=>'b'})
并不总是等于createsig({:b=>'b',:a=>'a'})
。
创建签名字符串来满足此需求的最佳方法是什么?
注意:对于我们之间的细节,我知道你不能 JSON.generate()
数字或字符串。在这些情况下,我只需直接调用 MD5.hexdigest()
即可。
I need to create a signature string for a variable in Ruby, where the variable can be a number, a string, a hash, or an array. The hash values and array elements can also be any of these types.
This string will be used to compare the values in a database (Mongo, in this case).
My first thought was to create an MD5 hash of a JSON encoded value, like so: (body is the variable referred to above)
def createsig(body)
Digest::MD5.hexdigest(JSON.generate(body))
end
This nearly works, but JSON.generate does not encode the keys of a hash in the same order each time, so createsig({:a=>'a',:b=>'b'})
does not always equal createsig({:b=>'b',:a=>'a'})
.
What is the best way to create a signature string to fit this need?
Note: For the detail oriented among us, I know that you can't JSON.generate()
a number or a string. In these cases, I would just call MD5.hexdigest()
directly.
发布评论
评论(6)
我很快就编写了以下代码,没有时间在工作中真正测试它,但它应该可以完成工作。如果您发现任何问题,请告诉我,我会查看。
这应该正确地展平并对数组和散列进行排序,并且您需要一些看起来非常奇怪的字符串才能避免任何冲突。
I coding up the following pretty quickly and don't have time to really test it here at work, but it ought to do the job. Let me know if you find any issues with it and I'll take a look.
This should properly flatten out and sort the arrays and hashes, and you'd need to have to some pretty strange looking strings for there to be any collisions.
如果您只能获取
body
的字符串表示形式,并且每次都不能以不同的顺序返回 Ruby 1.8 哈希值,那么您就可以可靠地对该字符串表示形式进行哈希处理。让我们开始使用一些猴子补丁:现在任何对象(问题中提到的类型)都会通过返回用于创建校验和的可靠密钥来响应
md5key
,因此:示例:
注意:该哈希表示不编码结构,仅编码值的串联。因此 ["a", "b", "c"] 的哈希值与 ["abc"] 相同。
If you could only get a string representation of
body
and not have the Ruby 1.8 hash come back with different orders from one time to the other, you could reliably hash that string representation. Let's get our hands dirty with some monkey patches:Now any object (of the types mentioned in the question) respond to
md5key
by returning a reliable key to use for creating a checksum, so:Example:
Note: This hash representation does not encode the structure, only the concatenation of the values. Therefore ["a", "b", "c"] will hash the same as ["abc"].
这是我的解决方案。我遍历数据结构并构建一个连接成单个字符串的片段列表。为了确保所看到的类类型影响哈希值,我注入了一个 unicode 字符,该字符一路上对基本类型信息进行编码。 (例如,我们想要 ["1", "2", "3"].objsum != [1,2,3].objsum)
我这样做是为了对 Object 进行改进,它很容易移植到猴子补丁中。要使用它,只需需要该文件并运行“using ObjSum”。
Here's my solution. I walk the data structure and build up a list of pieces that get joined into a single string. In order to ensure that the class types seen affect the hash, I inject a single unicode character that encodes basic type information along the way. (For example, we want ["1", "2", "3"].objsum != [1,2,3].objsum)
I did this as a refinement on Object, it's easily ported to a monkey patch. To use it just require the file and run "using ObjSum".
只是我的 2 美分:
Just my 2 cents:
如今,有一个正式定义的 JSON 规范化方法,正是出于这个原因: https://datatracker.ietf.org/doc/html/draft-rundgren-json-canonicalization-scheme-16
有一个ruby 实现在这里: https://github.com/dryruby/json-canonicalization
These days there is a formally defined method for canonicalizing JSON, for exactly this reason: https://datatracker.ietf.org/doc/html/draft-rundgren-json-canonicalization-scheme-16
There is a ruby implementation here: https://github.com/dryruby/json-canonicalization
根据您的需要,您甚至可以调用 ary.inspect 或 ary.to_yaml 。
Depending on your needs, you could call
ary.inspect
orary.to_yaml
, even.