Лучший способ создать уникальный токен в Rails?
вот что я использую. Токен не обязательно должен быть услышан, чтобы угадать, это больше похоже на короткий идентификатор url, чем что-либо еще, и я хочу сохранить его коротким. Я следил за некоторыми примерами, которые я нашел в интернете, и в случае столкновения,Я думаю приведенный ниже код воссоздаст токен,но я не уверен. Мне любопытно увидеть лучшие предложения, хотя, поскольку это кажется немного грубым по краям.
def self.create_token
random_number = SecureRandom.hex(3)
"1X#{random_number}"
while Tracker.find_by_token("1X#{random_number}") != nil
random_number = SecureRandom.hex(3)
"1X#{random_number}"
end
"1X#{random_number}"
end
мой столбец базы данных для маркера является уникальным индексом, и я также использую validates_uniqueness_of :token
на модели, но поскольку они создаются в пакетах автоматически на основе действий пользователя в приложении (они размещают заказ и покупают токены, по существу), невозможно, чтобы приложение выдавало ошибку.
я мог бы также, я думаю, уменьшить вероятность столкновений, добавить другую строку в конце, что-то сгенерированное на основе времени или что-то в этом роде, но я не хочу, чтобы токен получался слишком длинным.
10 ответов
-- Update --
по состоянию на 9 января, 2015. решение теперь реализовано в рельсы 5 реализация защищенного токена ActiveRecord.
-- Rails 4 & 3 --
просто для справки, создание безопасного случайного токена и обеспечение его уникальности для модели (при использовании Ruby 1.9 и ActiveRecord):
class ModelName < ActiveRecord::Base
before_create :generate_token
protected
def generate_token
self.token = loop do
random_token = SecureRandom.urlsafe_base64(nil, false)
break random_token unless ModelName.exists?(token: random_token)
end
end
end
Edit:
@kain предложил, и я согласился, чтобы заменить begin...end..while
С loop do...break unless...end
в этом ответе, потому что предыдущая реализация может быть удалена в будущем.
Edit 2:
С рельсами 4 и проблемами, я бы рекомендовал переместить это в беспокойство.
# app/models/model_name.rb
class ModelName < ActiveRecord::Base
include Tokenable
end
# app/models/concerns/tokenable.rb
module Tokenable
extend ActiveSupport::Concern
included do
before_create :generate_token
end
protected
def generate_token
self.token = loop do
random_token = SecureRandom.urlsafe_base64(nil, false)
break random_token unless self.class.exists?(token: random_token)
end
end
end
Райан Бейтс использует немного кода в своем Railscast на бета-приглашения. Это создает 40-символьную буквенно-цифровую строку.
Digest::SHA1.hexdigest([Time.now, rand].join)
есть несколько довольно скользких способов сделать это, продемонстрированных в этой статье:
мой любимый список таков:
rand(36**8).to_s(36)
=> "uur0cj2h"
Это может быть поздний ответ, но чтобы избежать использования цикла, вы также можете вызвать метод рекурсивно. На мой взгляд, он выглядит и чувствует себя немного чище.
class ModelName < ActiveRecord::Base
before_create :generate_token
protected
def generate_token
self.token = SecureRandom.urlsafe_base64
generate_token if ModelName.exists?(token: self.token)
end
end
Если вы хотите что-то, что будет уникальным, вы можете использовать что-то вроде этого:
string = (Digest::MD5.hexdigest "#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}")
однако это создаст строку из 32 символов.
есть, однако, другой способ:
require 'base64'
def after_create
update_attributes!(:token => Base64::encode64(id.to_s))
end
например, для id, такого как 10000, сгенерированный токен будет похож на "MTAwMDA=" (и вы можете легко декодировать его для id, просто сделайте
Base64::decode64(string)
Это может быть полезно :
SecureRandom.base64(15).tr('+/=', '0aZ')
Если вы хотите удалить какой-либо специальный символ, чем положить в первый аргумент '+/=' и любой символ, помещенный во второй аргумент '0aZ' и 15-это длина здесь .
и если вы хотите удалить лишние пробелы и символ новой строки, чем добавить такие вещи, как :
SecureRandom.base64(15).tr('+/=', '0aZ').strip.delete("\n")
надеюсь, что это поможет кому-нибудь.
попробуйте так:
начиная с Ruby 1.9, поколение uuid встроено. Используйте .
создание GUID в Ruby
Это было полезно для меня
вы можете пользователь has_secure_token https://github.com/robertomiranda/has_secure_token
очень прост в использовании
class User
has_secure_token :token1, :token2
end
user = User.create
user.token1 => "44539a6a59835a4ee9d7b112b48cd76e"
user.token2 => "226dd46af6be78953bde1641622497a8"