2014-04-07 74 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

相關問題