我想在控制器中为"user_info_token"列的用户生成一个令牌。然而,我想检查当前没有用户拥有该令牌。这段代码是否足够?
begin
@new_token = SecureRandom.urlsafe_base64
user = User.find_by_user_info_token(@new_token)
end while user != nil
@seller.user_info_token = @new_token
还有更简单的方法吗?
我想在控制器中为"user_info_token"列的用户生成一个令牌。然而,我想检查当前没有用户拥有该令牌。这段代码是否足够?
begin
@new_token = SecureRandom.urlsafe_base64
user = User.find_by_user_info_token(@new_token)
end while user != nil
@seller.user_info_token = @new_token
还有更简单的方法吗?
# Base-64 (url-safe) encoded bytes, 22 characters long
SecureRandom.urlsafe_base64(16)
# Base-36 encoded bytes, naturally url-safe, ~25 characters long
SecureRandom.hex(16).to_i(16).to_s(36)
# Base-16 encoded bytes, naturally url-safe, 32 characters long
SecureRandom.hex(16)
@seller.user_info_token = loop do
token = SecureRandom.urlsafe_base64
break token unless User.exists?(user_info_token: token)
end
有些干净的东西,但可能存在重复(尽管很少):
@seller.user_info_token = SecureRandom.uuid
编辑:当然,在你的:user_info_token
中添加唯一索引。这将更快地搜索具有相同令牌的用户,并且如果恰好在精确相同的时刻保存了2个具有相同令牌的用户,则会引发异常!
我有很多模型需要应用独特的标记。因此,我在app/models/concerns/tokened.rb
中创建了一个Tokened
关注点。
module Tokened
extend ActiveSupport::Concern
included do
after_initialize do
self.token = generate_token if self.token.blank?
end
end
private
def generate_token
loop do
key = SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
break key unless self.class.find_by(token: key)
end
end
end
include Tokened
class User
has_secure_token
end
由于Rails 5尚未发布,您可以使用has_secure_token gem。此外,您可以查看我的博客文章以获取更多信息:https://coderwall.com/p/kb97gg/secure-tokens-from-rails-5-to-rails-4-x-and-3-x
master
分支上 https://github.com/rails/rails/blob/master/activerecord/lib/active_record/secure_token.rb - Batmannew_token = Digest::MD5.hexdigest(Time.now.to_i.to_s + rand(999999999).to_s)
user.user_info_token = new_token
您可以尝试以下一些技巧来获取唯一的令牌,这是我在我的项目中使用的非常简单的方法 -
CREDIT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
def create_credit_key(count = 25)
credit_key = ""
key = CREDIT_CHARS.length
for i in 1..count
rand = Random.rand((0.0)..(1.0))
credit_key += CREDIT_CHARS[(key*rand).to_i].to_s
end
return credit_key
end
使用摘要算法会更容易,但我在这里尝试生成不使用任何算法的摘要。