我正在尝试使用算法为我的rails应用中的模型生成唯一的非顺序令牌。
例如:
MyModel.create.token #=> '183685'
MyModel.create.token #=> '456873'
MyModel.create.token #=> '813870'
我能想到的唯一方法是创建一个随机的东西,检查碰撞,然后重试。对我来说,这似乎是一种肮脏的代码,以一种蛮力的方式。
class MyModel < ActiveRecord::Base
before_create :set_token
def set_token
existing_model_count = nil
# Loop while we have a token that already belongs to an existing model.
while existing_model_count.nil? || existing_model_count > 0
random_token = TokenGenerator.random_token
existing_model_count = MyModel.where(token: random_token).count
end
# Loop exited, meaning we found an unused token.
self.token = random_token
end
end
有没有更好的方法来执行此操作,不涉及将迭代未知次数的while
循环?
虽然这里的示例是ruby,但这是一种适用于任何语言的通用算法问题,因此欢迎使用其他语言的解决方案。
答案 0 :(得分:6)
如果你的“令牌”是某个范围内的整数值并且你事先知道了令牌的数量,那么简单的Bob Floyd算法(在Bentley的“Programming Peals”或here中描述)会生成一个唯一的随机数没有重试。它使用额外的存储来“标记”已经使用过的数字,但如果已经采用了随机生成的数字(即没有重复的试错迭代),它仍巧妙地设法立即得出一个未使用的数字。
该算法的一个问题是,尽管它生成的数字通常不是有序的,但顺序仍然不是完全随机的。换句话说,即使算法保证从该范围中选取的每个单独数字的均匀分布,也不能保证所有可能的结果序列中所得序列的均匀分布。
对你来说这是否是一件大事 - 只有你可以决定。如果您生成的令牌数量与范围的长度相比较小,则此算法将提供非常令人满意的结果。如果令牌的数量接近范围的长度,则该算法将生成“几乎已排序”的序列。
答案 1 :(得分:2)
你能做到的一种方法是混淆数字。我在文章Obfuscating Sequential Keys中详细解释了这一点。代码示例是C#,但不应该难以翻译。
答案 2 :(得分:2)
每隔几个小时运行一次cronjob,重新填充带有未使用标识符的Redis集合。让它在后台运行,所以当你需要它时,只需将它从Redis集合中弹出。
答案 3 :(得分:2)
cipher = OpenSSL::Cipher::AES.new(128, :CBC).encrypt
cipher.update(MyModel.create.object_id.to_s(36))
答案 4 :(得分:1)
从序列中取出数字。实施一个feistel网络来加扰数字。 我找到的一个例子是:https://gist.github.com/Xeoncross/3715367
答案 5 :(得分:1)
您可以使用SecureRandom.uuid
。我认为它保证了唯一的随机UUID令牌。