Как избежать порядковых, целых маршрутов (инкрементные идентификаторы) в маршрутах rails ‘show’?

#ruby-on-rails #rails-routing

#ruby-on-rails #rails-маршрутизация

Вопрос:

Самый простой MRE — это rails g scaffold users

Когда мы создаем пользователей, их id будет 1, 2, 3, 4 и т.д., А их маршрут ‘show’ будет /show/:id

Иногда мы не хотим, чтобы пользователи веб-сайта точно знали, сколько у нас пользователей — есть простой способ запутать это?

Я могу придумать способ сделать это вручную, добавив дополнительный столбец при регистрации со случайным 12-значным целым числом, но также проверив, что случайно сгенерированное целое число еще не существует.

Но мне интересно, есть ли более разумный способ?

Примечания

  • Пример:https://www.youtube.com/watch?v=Gzj723LkRJY (где Gzj723LkRJY предположительно генерируется случайным образом, а не что-то предсказуемое)

  • Пример того, почему инкрементные идентификаторы могут быть плохой идеей (~ 30 секунд из 2m 52s)

    многие плохо спроектированные сайты используют инкрементные счетчики. Это может рассказать вашим конкурентам, сколько у вас клиентов.. Это может позволить людям легко загружать все ваши записи

  • ..и еще один пример того, почему инкрементные идентификаторы / маршруты могут быть плохими:

каждый пост содержал числовой идентификатор, который был увеличен с идентификатора самого последнего опубликованного

Комментарии:

1. Насколько запутанный вы пытаетесь получить? Вы могли бы запустить первичный ключ пользовательской таблицы вашей БД с некоторым большим случайным числом. Таким образом, первым пользователем в БД будет 9482827383, а вторым будет 9482827384. Или вы могли бы скрыть этот параметр из адреса, но кто-то может открыть панель разработчика в браузере и посмотреть, каковы параметры запроса.

2. Вы могли бы рассмотреть возможность перехода на использование UUID в качестве первичных ключей вместо целых чисел. Проверьте guides.rubyonrails.org /… для описания с Postgres.

Ответ №1:

Rails на самом деле не заботится о том, что вы используете в качестве основного идентификатора для своих моделей.

Когда мы создаем пользователей, их id будет 1, 2, 3, 4 и т.д., А их маршрут ‘show’ будет /show/:id

Неверно. Маршруты будут /users/?(:id) . Запустите rails routes | grep users , чтобы увидеть сгенерированные маршруты.

Ваши маршруты на самом деле будут соответствовать не только целым числам, но и любым символам, кроме ограниченного подмножества ( . и / в частности) именованному :id сегменту.

Таким образом, это будет соответствовать следующему действию users #show:

 GET /users/1
GET /users/gabba-gabba-hey
GET /users/gabba gabba hey
  

Но не:

 GET /users/1/2
GET /users/gabba/gabba
GET /users/gabba/gabba/hey
  

Автоинкрементные целочисленные столбцы используются по умолчанию в Rails в качестве первичного ключа, поскольку они просты, коротки и выполняют работу в 99% случаев. Обычно, если вы переключаетесь на UUID, причина в том, что вы работаете в масштабе, где вам нужно несколько баз данных, и последовательная генерация идентификаторов не сокращает ее. Переключение идентификатора на что-то случайно сгенерированное бесконечно усложняет угадывание, но все еще не заменяет фактическую авторизацию доступа к ресурсам, поскольку они все еще могут просочиться в журналы, электронные письма и т.д.

Я могу придумать способ сделать это вручную, добавив дополнительный столбец при регистрации со случайным 12-значным целым числом, но также проверив, что случайно сгенерированное целое число еще не существует. Но мне интересно, есть ли более разумный способ?

ДА. Не изобретайте велосипед.

Ruby уже имеет встроенный метод SecureRandom#uuid, который генерирует UUID в соответствии с RFC 4122:

 class User < ApplicationRecord
  def generate_uuid
    loop do
      self.uuid = SecureRandom.uuid
      break unless User.exists?(uuid: self.uuid)
    end
  end
end
  

Поскольку риск столкновения здесь чрезвычайно низок, этот цикл может выполняться не более одного раза, и он просто выполняет EXIST запрос по (надеюсь) индексированному первичному ключу, поэтому стоимость относительно низкая.

Используя не только целые числа, но и буквы, вы можете генерировать более короткие идентификаторы с меньшей вероятностью столкновения.

Если вы используете базу данных, которая имеет встроенную поддержку UUID, такую как Postgres, это лучшая альтернатива, поскольку эта задача действительно лучше всего решается на уровне базы данных, поскольку это позволяет избежать раздувания приложения и снижает накладные расходы.

Ответ №2:

Вы можете использовать UUID , и это даст вам случайный безопасный токен, который никто не сможет легко понять серию пользователей.

миграция выглядит следующим образом

 create_table :users, id: :uuid do |t|
      t.string   :name
      t.string   :phone
      ....
      t.timestamps
    end
  

Я надеюсь, что это должно вам помочь.

Комментарии:

1. Отклонено, поскольку этот ответ просто предполагает, что используется Postgres или другая база данных с собственными UUID.