Rails,ruby:SecureRandom.urlsafe_base64需要检查令牌的唯一性吗?

时间:2014-04-07 18:02:20

标签: ruby random ruby-on-rails-4 unique

我需要为存储在我的数据库中的用户提供唯一的令牌。在我生成令牌的那一刻,我在使用它之前在DB中检查它的唯一性。这是我实际需要进行的测试,还是我在浪费时间?

我已经查看了Ruby 2.0.0 API for SecureRandom并且它没有澄清我是否可以信任"唯一性与否。

我知道没有任何随机价值可以真正成为"独特的"并且存在有限数量的可能性。但是使用32位十六进制值,我有信心在我的应用程序中再也不会遇到相同的值,但想知道是否有人知道" gotcha"遇到这种情况。

另一个考虑是使用SecureRandom.uuid,但这基本上是相同的情况。

# usage
user.password_reset_token = Generator.unique_token_for_user(:password_reset_token)

# Performs DB query to ensure uniqueness
class Generator
  def self.unique_token_for_user(attribute)
    begin
      token = SecureRandom.urlsafe_base64(32)
    end while User.exists?(attribute => token)

    token
  end
end

3 个答案:

答案 0 :(得分:10)

SecureRandom.uuid生成uuids。 UUID长128位,可以保证跨空间和时间的唯一性。与urlsafe_base64不同,它们设计为全球唯一。请参阅RFC4122

答案 1 :(得分:5)

它并不能确保唯一性,但正如 svoop 所说,你两次获得相同结果的可能性极小。

我的建议是:如果你需要的只是随机的,独特的和不可饶恕的令牌,而你没有成千上万的用户,那么就不必担心使用它。

如果绝对想要唯一令牌(例如,有一些法律要求),则组合与用户关联的唯一字段(例如用户电子邮件)和随机盐,并对结果进行哈希处理。

一个天真的实现将是:

require 'securerandom'
require 'digest/md5'


def generate_user_token(user)
  digest(user.email + random_salt)
end


def random_salt
  SecureRandom.urlsafe_base64
end


def digest(string)
  Digest::MD5.hexdigest string
end

答案 2 :(得分:4)

不,你的生命中不会发现重复。

32是在将其转换为urlsafe base64字符串之前生成的随机数的长度(以字节为单位),因此重复的可能性大约是1到10'000'000'000'000'000 “000'000'000'000'000。那是10e31,宇宙只有43e17秒。