2014-04-07 125 views
7

我需要存储在我的数据库中的用户的唯一令牌。在我生成令牌时,我在使用它之前检查数据库中的唯一性。这是我真正需要执行的测试还是我浪费时间?Rails,ruby:需要检查SecureRandom.urlsafe_base64是否具有令牌唯一性?

我看过Ruby 2.0.0 API for SecureRandom,它并没有说明我是否可以“信任”唯一性。

我知道没有随机值真的可以是“唯一的”,并且存在有限数量的可能性。但是,对于32位的十六进制值,我确信我永远不会在我的应用程序中再次遇到相同的值,但想问问有没有人知道这种情况的“陷阱”。

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

回答

7

SecureRandom.uuid生成的UUID。 UUID的长度为128位,可以保证空间和时间的唯一性。它们被设计成全球独一无二的,不像urlsafe_base64。见RFC4122

+0

@tompave发布的答案也是可行的。但是,使用SecureRandom.uuid生成器不需要额外的工作,因此我将其标记为我的特定问题(“有保证”的独特标记方式)的最佳解决方案。 UUID规范4“应该”还有122个随机位(来自我读的),所以它不仅是唯一的,而且它也是安全的,因为用户不容易“猜测”另一个UUID。 –

4

不,你不会看到你的寿命重复。

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

4

这并不能保证唯一性,但如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 
+0

这是一个很好的解决方案。但是,我使用了SecureRandom.uuid实现,因为这需要较少的工作,同时仍然确保唯一性/安全性:) –

+0

我更喜欢此解决方案,它更安全。 – JellyFishBoy

相关问题