ruby:SecureRandom.urlsafe_base64是否需要检查令牌的唯一性?

ruby:SecureRandom.urlsafe_base64是否需要检查令牌的唯一性?,ruby,random,ruby-on-rails-4,unique,Ruby,Random,Ruby On Rails 4,Unique,我需要存储在数据库中的用户的唯一令牌。当我生成一个令牌时,我会在使用它之前在DB中检查它的唯一性。这是我真正需要执行的测试还是我在浪费时间 我已经看过了,它并没有澄清我是否可以“相信”这种独特性 我知道没有一个随机值真的是“唯一的”,而且有有限的可能性。但有了32位的十六进制值,我相信我再也不会在我的应用程序中遇到相同的值,但我想问一下,是否有人知道这种情况下会出现“gotcha” # usage user.password_reset_token = Generator.unique_toke

我需要存储在数据库中的用户的唯一令牌。当我生成一个令牌时,我会在使用它之前在DB中检查它的唯一性。这是我真正需要执行的测试还是我在浪费时间

我已经看过了,它并没有澄清我是否可以“相信”这种独特性

我知道没有一个随机值真的是“唯一的”,而且有有限的可能性。但有了32位的十六进制值,我相信我再也不会在我的应用程序中遇到相同的值,但我想问一下,是否有人知道这种情况下会出现“gotcha”

# 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
另一个考虑因素是使用
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

不,你不会在你的寿命中看到一个复制品


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

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

我的建议是:如果你所需要的只是随机的、唯一的和不可用的代币,而你没有成千上万的用户,那么使用它就不用担心了

如果您绝对想要唯一的令牌(例如,有一些法律要求),则将与用户相关联的唯一字段(例如,用户电子邮件)与随机salt组合,并对结果进行散列

一个简单的实现是:

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

SecureRandom.uuid
生成uuid。UUID的长度为128位,可以保证跨空间和时间的唯一性。它们被设计为全球唯一,不像
urlsafe\u base64
。参见。

由@tompave发布的答案也是可行的。但是,使用SecureRandom.uuid生成器不需要任何额外的工作,因此我将其标记为我的特定问题的最佳解决方案(“唯一令牌的保证”方式)。UUID规范4“应该”也有122个随机位(从我读到的),所以它不仅是唯一的,而且是安全的,因为用户不容易“猜测”另一个UUID。这是一个很好的解决方案。然而,我选择了SecureRandom.uuid实现,因为这在确保唯一性/安全性的同时,对我来说需要更少的工作:)我更喜欢这个解决方案,更安全。不是100%正确。我刚在生产中得到一份复制件。我想是幸运吧?:)