Как сделать идентификаторы модели в Rails непредсказуемыми и случайными

Я пишу приложение rails, которое по своей природе НЕ МОЖЕТЕ требовать от пользователей регистрации, и поэтому не может использовать аутентификацию в качестве обычного средства защиты записей. (Я знаю, я знаю...) Информация пользователя здесь ограничена адресами электронной почты. Поэтому мне нужен способ сделать мои идентификаторы модели непредсказуемыми, чтобы другие идентификаторы не могли быть легко угаданы. (Я знаю, я знаю...)

Я пробовал использовать плагины, такие как uuidtools, для рандомизации идентификаторов, поскольку записи создаются так:

require 'uuidtools'
class Post < ActiveRecord::Base 
 def before_create() 
  self.id = OpenSSL::Digest.SHA1.hexdigest(UUID.timestamp_create()) 
 end 
end 

... Сначала это выглядит хорошо, но забавные вещи случаются. ActiveRecord иногда пытается вставить значение 0 в id, и я получаю такие ошибки, как "не удается найти сообщение с id = 0" и т.д.

У меня закончились идеи. Может ли кто-нибудь помочь? Спасибо.

Ответы

Ответ 1

В вашей модели сделайте следующее:

before_create :randomize_id

...

private
def randomize_id
  begin
    self.id = SecureRandom.random_number(1_000_000)
  end while Model.where(id: self.id).exists?
end

Ответ 2

Лучший способ - использовать SecureRandom.uuid, который генерирует UUID V4 (универсально уникальный идентификатор).

Он практически полностью случайен и уникален (вероятность столкновения - это что-то вроде одного десятка триллионов): https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29

Это должно выполнить задание:

class Post < ActiveRecord::Base
 before_create :generate_random_id

 private 
 def generate_random_id
   self.id = SecureRandom.uuid
 end 
end

Или, если вы используете Rails >= 4 и PostgreSQL, вы можете создать его для вас:

create_table :posts, id: :uuid do |t|
  ...
end

Ответ 3

Там есть плагин, который должен делать то, что вы хотите:

http://codesnipers.com/?q=using-uuid-guid-as-primary-key-in-rails

(Все извиняются за цензуры SO за то, что они не вставлялись во всю статью. В моей защите он загружался ссылками и форматированием, для чего потребовалось бы немало усилий для репликации. Не говоря уже о том, что мы будем грабить страницу автора трафика и потенциального дохода.)

Ответ 4

Вещь, которая здесь не так, заключается в том, что self.id требует int и OpenSSL:: Digest.SHA1.hexdigest(UUID.timestamp_create()) возвращает строку с нечисловыми символами, которая приведет к значению '0 'фактически хранится в базе данных

Ответ 5

Альтернативой является создание маркера или контрольной суммы или что-то другое во втором столбце во время создания записи, и во всех случаях, когда ваши контроллеры запрашивают объект, используйте Model.find_by_id_and_token.

Вы всегда будете генерировать URL-адреса, содержащие и требующие как идентификатор, так и токен.