Разработка первичного ключа REST API MySQL

Мы создаем новый REST API и должны принять несколько решений относительно первичного ключа и idempotency_key. У нашего API много пользователей, и пользователям разрешено искать только те объекты, которые им принадлежат. Запросы аутентифицируются, поэтому мы знаем, что userId связан с данным запросом.

Обеспокоенные свойства:

  • userId Идентификатор пользователя.
  • idempotenyKey Ключ идемпотентности, используемый в идемпотентных запросах к API. Уникальный для каждого пользователя.

Предположим, существует гипотетическая таблица Cars с конечной точкой GET .../cars/{id}, на которой мы будем основывать наше обсуждение.

Параметры

Вариант 1. Используйте сочетание userId и idempotencyKey в качестве первичного ключа

CREATE TABLE Cars (
 userId VARCHAR(255) NOT NULL,
 idempotencyKey VARCHAR(255) NOT NULL,
 description VARCHAR(255),
 PRIMARY KEY (userId, idempotencyKey),
 INDEX user_index (userId)
);

Поиск товара: GET .../cars/{idempotencyKey}

Мысли:

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

Вариант 2 - Использование хеша userId + idempotencyKey в качестве первичного ключа

CREATE TABLE Cars (
 id VARCHAR(255) NOT NULL,
 userId VARCHAR(255) NOT NULL,
 idempotencyKey VARCHAR(255) NOT NULL,
 description VARCHAR(255),
 PRIMARY KEY (id),
 INDEX user_index (userId)
);

При вставке рассчитывали id = hash(userId + idempotencyKey).

Поиск товара: GET .../cars/{id}

Мысли:

  • Первичные ключи невозможно определить.
  • Это дополнительно предотвращает возможность угроз безопасности при операциях с ids.
  • Больше не составной первичный ключ.
  • В отличие от варианта 3, не требует уникального ограничения на (userId, idempotencyKey).

Вариант 3 - Генерация первичного ключа uuid

CREATE TABLE Cars (
 id VARCHAR(255) NOT NULL,
 userId VARCHAR(255) NOT NULL,
 idempotencyKey VARCHAR(255) NOT NULL,
 description VARCHAR(255),
 PRIMARY KEY (id),
 INDEX user_index (userId),
 CONSTRAINT unique_by_user UNIQUE (userId, idempotencyKey)
);

При прошивке ставили id = UUID.randomUUID().

Поиск товара: GET .../cars/{id}

Мысли:

  • id абсолютно непостижим и не привязан к каким-либо бизнес-данным.
  • Требуется дополнительный индекс.

Вариант 4 - автоматически увеличиваемый первичный ключ, который никогда не открывается пользователю

CREATE TABLE Cars (
 id INT NOT NULL AUTO_INCREMENT,
 userId VARCHAR(255) NOT NULL,
 idempotencyKey VARCHAR(255) NOT NULL,
 description VARCHAR(255),
 PRIMARY KEY (id),
 INDEX user_index (userId),
 CONSTRAINT unique_by_user UNIQUE (userId, idempotencyKey)
);

Есть несколько способов выполнить поиск. Поиск может быть основан исключительно на idempotencyKey, то есть: GET .../cars/{idempotencyKey}

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

Мысли:

  • Первичный ключ никогда не открывается пользователю, что является довольно распространенной практикой.
  • Обеспечивает большую гибкость при изменении бизнес-логики (хотя для фундаментальных концепций, таких как userId и idempotencyKey, я не вижу, как они изменятся).
  • Первичный ключ - это INT, поэтому он меньше. Это позволяет использовать меньшие индексы и, возможно, большую производительность.
  • Снова требуется дополнительный индекс.

Ищу совет, какой подход выбрать. Очень важно учитывать производительность и масштаб.

Спасибо!

Я обрабатываю что-то подобное: отправляю идентификатор пользователя в заголовке Authorization (идентификатор пользователя будет заявкой в ​​JWT в заголовке авторизации), а затем использую его для сравнения с идентификатором пользователя в пути запроса, например /user/1. Если они совпадают, то аутентифицированный пользователь может действовать от имени пользователя в пути запроса. Это очень безопасно, потому что идентификатор пользователя в заголовке авторизации никогда не может быть изменен, пока никто не знает ваш секретный ключ. Просто имейте в виду, что JWT может использоваться злонамеренно, поэтому делайте это только в том случае, если пользователь действует на себя, а не на кого-то другого.

Lansana Camara 16.05.2018 20:54

Есть ли в таблице пользователя (я полагаю, у вас есть таблица пользователей) столбец с idempotency_key? Если это так, вы сохраняете один и тот же дубликат данных, и вам следует удалить idempotency_key из таблицы car .. Вы можете просто найти отношение idempotencyKey между пользователем и автомобилем с помощью этого запроса SELECT * FROM user INNER JOIN car ON user.id = car.userId WHERE user.idempotencyKey = "key"

Raymond Nijland 16.05.2018 21:18

Для дополнительной безопасности вы можете добавить ограничение, с каких IP-адресов можно использовать idempotencyKey.

Raymond Nijland 16.05.2018 21:22

Для аутентификации мы используем JWT с userId в полезной нагрузке. Меня больше интересуют отзывы о возможных вариантах первичного ключа в отношении схемы базы данных. @RaymondNijland, что касается таблицы пользователей, мы также можем предположить, что она существует и что существует ограничение внешнего ключа на свойство userId на автомобилях. Невозможно удалить idempotencyKey из Cars, поскольку у пользователя может быть много автомобилей, и для запросов на создание автомобилей необходимо принудительно применять идемпотентность.

TimJ 16.05.2018 22:37
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
4
1 002
0

Другие вопросы по теме