我需要为存储在我的数据库中的用户提供唯一的令牌。在我生成令牌的那一刻,我在使用它之前在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
答案 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秒。