我想生成一个完全随机的“唯一”(我将确保使用我的模型)给定的标识符(长度可能不同)长度包含数字,字母和特殊字符
例如:
161551960578281|2.AQAIPhEcKsDLOVJZ.3600.1310065200.0-514191032|
有人可以在Ruby on Rails中建议最有效的方法吗?
编辑:重要提示: 如果可能,请评论您提出的解决方案的效率,因为每次用户进入网站时都会使用此解决方案!
由于
答案 0 :(得分:12)
将此用作访问令牌与UUID不同。您不仅需要伪随机性,还需要加密安全PRNG。如果你真的不关心你使用的是什么字符(它们没有向安全性添加任何内容),你可以使用以下内容,生成一个URL安全的Base64编码的访问令牌。如果将令牌附加到URL,URL安全性就变得很重要,类似于某些Java Web应用程序所做的那样:“http://www.bla.com/jsessionid=”。如果您为此目的使用原始Base64字符串,则会产生可能无效的URL。
require 'securerandom'
def produce_token(length=32)
token = SecureRandom.urlsafe_base64(length)
end
获得重复的概率等于2 ^( - 长度)。由于输出将采用Base64编码,因此实际输出长度为4/3 *。如果已安装,则基于本机OpenSSL PRNG实现,因此在性能方面应该非常高效。如果没有安装OpenSSL扩展,如果可用,将使用/dev/urandom
,最后,如果您在Windows计算机上,CryptGenRandom将用作后备。这些选项中的每一个都应该具有足够的性能。例如,在我的笔记本电脑上运行produce_token
一百万次完成~6s。
答案 1 :(得分:3)
Universally Unique Identifieres - UUIDs生成自己很棘手;-)如果您想要真正可靠的内容,请使用uuid4r gem并将其与UUID4R::uuid(1)
一起调用。这将根据时间和硬件ID(计算机mac地址)吐出一个uuid。因此,如果在同一时间生成,它在多台机器上甚至是唯一的。
uuid4r的要求是ossp-uuid c library,您可以使用自己选择的数据包管理器进行安装(例如,apt-get install libossp-uuid libossp-uuid-dev
在debian上或brew install ossp-uuid
在mac上,homebrew或者通过手动下载和编译当然。
使用uuid4r而不是手动(更简单?)实现的优势在于它是a)真正独特的,而不仅仅是某种伪随机数生成器,有时是可靠的"和b)通过使用c库的原生扩展来快速(即使使用更高的uuid版本)
require 'rubygems'
require 'uuid4r'
UUID4R::uuid(1) #=> "67074ea4-a8c3-11e0-8a8c-2b12e1ad57c3"
UUID4R::uuid(1) #=> "68ad5668-a8c3-11e0-b5b7-370d85fa740d"
更新: 关于速度,请参阅我的(完全不科学!)超过50k迭代的小基准
user system total real
version 1 0.600000 1.370000 1.970000 ( 1.980516)
version 4 0.500000 1.360000 1.860000 ( 1.855086)
所以在我的机器上,生成一个uuid需要大约0.4毫秒(请记住,我在整个基准测试中使用了50000次迭代)。希望你的速度足够快
(遵循"基准")
require 'rubygems'
require 'uuid4r'
require 'benchmark'
n = 50000
Benchmark.bm do |bm|
bm.report("version 1") { n.times { UUID4R::uuid(1) } }
bm.report("version 4") { n.times { UUID4R::uuid(4) } }
end
heroku更新:gem是available on heroku as well
答案 2 :(得分:3)
最佳解决方案是:
require 'active_support/secure_random'
ActiveSupport::SecureRandom.hex(16) # => "00c62d9820d16b52740ca6e15d142854"
这将生成加密安全的随机字符串(即完全不可预测)
同样,您可以使用库来生成其他人建议的UUID。在这种情况下,请务必使用随机版本(版本4)并确保实现使用cryptosecure随机生成器。
与安全相关的任何内容,滚动自己并不是最好的主意(即使我也屈服于它,请看第一版!:-)。如果确实想要一个自制的随机字符串,这里重写了tybro0103
的方法:
require 'digest/sha1'
ALPHABET = "|,.!-0123456789".split(//) + ('a'..'z').to_a + ('A'..'Z').to_a
def random_string
not_quite_secure = Array.new(32){ ALPHABET.sample }.join
secure = Digest::SHA1.hexdigest(not_quite_secure)
end
random_string # => "2555265b2ff3ecb0a13d65a3d177b326733bc143"
请注意,它会散列随机字符串,否则可能会受到攻击。 表现应该类似。
答案 3 :(得分:2)
def random_string(length=32)
chars = (0..9).to_a.concat(('a'..'z').to_a).concat(('A'..'Z').to_a).concat(['|',',','.','!','-'])
str = ""; length.times {str += chars.sample.to_s}
str
end
结果:
>> random_string(42)
=> "a!,FEv,g3HptLCImw0oHnHNNj1drzMFM,1tptMS|rO"
答案 4 :(得分:0)
由于字符行为的改变,在Ruby 1.9和1.8中生成随机字母有点棘手。在1.9中执行此操作的最简单方法是生成要使用的字符数组,然后从该数组中随机抓取字符。 见http://snippets.dzone.com/posts/show/491
答案 5 :(得分:0)