Как сгенерировать уникальный идентификатор заказа (просто чтобы показать touser) с фактическим идентификатором заказа? - PullRequest
7 голосов
/ 22 марта 2011

ВНОВЬ РЕДАКТИРОВАТЬ: Я не хочу создавать другой вопрос, поэтому задавайте здесь.У меня такая же ситуация.Но на этот раз мне нужен алгоритм на языке Си.Может ли любое тело помочь мне.

У меня есть следующая таблица.

CREATE TABLE IF NOT EXISTS `j741_order` (
  `order_id` int(11) NOT NULL AUTO_INCREMENT,
  `buyer_id` int(11) NOT NULL,
  `subtotal` decimal(15,5) DEFAULT '0.00000',
  `discount` decimal(15,5) NOT NULL DEFAULT '0.00000',
  `shipping` decimal(15,5) DEFAULT '0.00000',
  `tax` decimal(15,5) DEFAULT '0.00000',
  `total` decimal(15,5) NOT NULL DEFAULT '0.00000',
  `currency` char(3) DEFAULT NULL,
  `status` int(11) NOT NULL DEFAULT '0',
  `created_date` datetime NOT NULL,
  `modified_date` datetime NOT NULL,
  PRIMARY KEY (`order_id`),
  KEY `idx_buyer_id` (`buyer_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

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

Как я могу получить этот Уникальный Случайный Идентификатор Заказа из исходного Заказа If

и получить исходный Идентификатор заказа из этого Случайного Идентификатора Заказа?

РЕДАКТИРОВАТЬ: Я не хочу создавать другие поля.

Ответы [ 7 ]

9 голосов
/ 22 марта 2011
  1. Создайте свой секретный ключ (любую строку) и сохраните в своих файлах конфигурации (или конфигурации БД).
  2. Создать уникальный идентификатор: $newId = hash_hmac('sha1', $orderId, $secret_key).'-'.$orderId;. Таким образом, ваши страницы заказа будут выглядеть как http://example.com/order/show/123456...absdef-123.
  3. Вы можете быстро получить оригинальный идентификатор заказа и проверить его:
 list($hash, $original) = explode($newId, '-', 2);
 if (hash_hmac('sha1', $original, $secret_key).'-'.$original === $hash)
 {
    // its a correct ID
 }
 else
 {
    // wrong hash, ignore it!
 }

Таким образом, оригинальный идентификатор является общедоступным, но пользователь не может заменить его в адресе сайта из-за неизвестной хешированной строки (первая часть уникального идентификатора).

9 голосов
/ 30 марта 2011

Если ваши требования:

  • Он должен быть обратимым (т. Е. С учетом просто"случайного" идентификатора, вы можете найти исходный идентификатор_порядка)
  • Без дополнительных столбцов
  • Вы вообще не хотите показывать пользователю оригинальный / внутренний код_ заказа.

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

Я также добавляю, что она должна быть удобной для человека, например кто-то может позвонить вам по телефону

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

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

Это строки шифрования, которые я использовал (я использовал это онлайн-скремблер слов вместо того, чтобы пытаться шифровать строку самостоятельно):

    $this->scramble1 = '0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
    $this->scramble2 = 'UKAH652LMOQ FBDIEG03JT17N4C89XPV-WRSYZ';

Итак, код для создания нашего дружественного человеку идентификатора заказа:

<?php

include 'encryption_class.php';

$crypt = new encryption_class();

$key = "A-COMPLETELY-RANDOM-KEY-THAT-I-HAVE-USED";
// Min length of 8 for encrypted string
$min_length = 8;

$order_id = 123456789;

print "Original: " . $order_id . PHP_EOL;

$encrypt_result = $crypt->encrypt($key, $order_id, $min_length); 

print "Encrypted: " . $encrypt_result . PHP_EOL;

// DECRYPT
$decrypt_result = $crypt->decrypt($key, $encrypt_result);

print "Decrypted: " . $decrypt_result . PHP_EOL;

?>

(Необходимо загрузить и сохранить файл * encryption_class * локально и включить его).

Я запустил этот код из командной строки и получил следующий вывод:

Original: 123456789
Encrypted: 2UD5UIK9S
Decrypted: 123456789

Теперь у нас есть наш короткий, удобный для человека order_id, который можно использовать в URL-адресе, таком как http://myapp.example.com/order/view/2UD5UIK9S,, и вам никогда не нужно отображать или передавать внутренний order_id своим пользователям.

Примечания:

Зашифрованный код будет уникальным, если ваш идентификатор_порядка уникален (так как это будет PK)

Это не должно использоваться в качестве процедуры шифрования / дешифрования пароля - не храните пароли, храните хэши.

Убедитесь, что ваш секретный ключ является случайным, сложным и содержит только символов в переменных $ scramble.

Затеняет только order_id.

Edit:

Хотя заполнение входной строки (order_id) генерирует определенное количество случайностей, вы можете объединить это с ответом @ biakaveron, чтобы создать URL-адрес типа http://myapp.example.com/order/view/5cc46aea44e898c3b4e1303eb18d8161302cd367/2UD5UIK9S

2 голосов
/ 22 марта 2011

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

Но вы можете добавить еще одно поле , которое будет действовать как идентификатор для пользователя :

  • Поле varchar(something) или char(something), которое улучшит отображение и будет сложнее угадать,
  • Это будет отображаться пользователю,
  • Там будет индекс UNIQUE,
  • Но это не будет иметь никакого технического значения для вашего кода.


A GUID может быть идеей - но у меня есть чувство, что это может быть слишком длинным ...

Как насчет чего-либо, основанного на первой букве имени пользователя, даты и некоторого случайного числа?
Было бы трудно догадаться, и все же они имеют немного смысла для пользователя ...

Конечно, вы не сможете рассчитать order_id по этому строковому идентификатору - но если он уникален, выполните простой запрос, и вы получите order_id обратно:

select order_id from your_table where nice_looking_id = '...';
0 голосов
/ 30 марта 2011

Как уже говорили другие, вы можете просто сгенерировать хеш идентификатора заказа с известной солью - тогда как компьютерам все равно, если номер заказа

854bf1176798d77ecaf6b66cbe71a8fc1b0c1847

или

36698

Существует большая разница, когда речь идет о мокрой посуде.

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

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

Конечно, общий объем заказов может считаться конфиденциальной информацией - в этом случае просто используйте порядковый номер, связанный с идентификатором пользователя. Хотя вы явно не указали, какую СУБД вы используете, я предполагаю, что это mysql или производная на основе движка, но следующее относится и к большинству реляционных СУБД:

Если вы добавите в таблицу столбец, описывающий пользователей со значением по умолчанию 0, то вы можете добавить триггеры в таблицу заказов, чтобы автоматически получать, увеличивать и обновлять это значение для каждой вставки в таблицу заказов - т.е. никаких изменений не требуется к коду в другом месте, за исключением поддержки «внешней» ссылки заказа. Конечно, вам нужно посеять это значение с соответствующим количеством уже размещенных заказов - что-то вроде ....

ALTER TABLE buyers ADD COLUMN buy_ref_last INTEGER DEFAULT 0;
ALTER TABLE orders ADD COLUMN buyer_order_ref INTEGER;
UPDATE orders o SET buyer_order_ref = (SELECT COUNT(*)
    FROM orders r WHERE r.buyer_id=o.buyer_id
    AND r.order_id<o.order_id);

(обратите внимание, что я подозреваю, что вышеизложенное не будет работать непосредственно в MySQL, ему не нравятся подвыборы в той же таблице, что и обновление / удаление - вам нужно развернуть логику в процедуру)

и ....

UPDATE buyers b SET buy_ref_last=(SELECT MAX(buyer_order_ref)
     FROM orders o WHERE o.buyer_id=b.id);
0 голосов
/ 29 марта 2011

$ original_id = [что бы то ни было;путем проверки равенства между dechex (substr ($ user_facing_id, 0, 5)) и substr (md5 (substr ($ user_facing_id, 5). $ salt).

0 голосов
/ 22 марта 2011

Другой, действительно простой способ - это кодирование OrderID в base64. Вы передаете клиенту кодированный идентификатор base64 вместо фактического идентификатора, а затем декодируете идентификатор, когда он возвращается. Я бы порекомендовал удалить знаки равенства с конца закодированной строки.

Преимущества:

  • Действительно быстрое и простое запутывание фактического идентификатора

Недостатки:

  • Вы должны помнить, чтобы расшифровать его
  • Умный пользователь легко поймет это из
0 голосов
/ 22 марта 2011

Вы можете немного выдумать, но я бы настоятельно рекомендовал добавить еще один столбец. Вот как я это сделаю с PHP.

// do your insert

// Retrieve last insert id
$orderId = mysql_insert_id();

// get the current timestamp
$time = time();

// Intersperse the $orderId into the $time to get a new "hash"
$orderId = explode("", (string)$orderId);
$time = explode("", (string)$time);

$orderIdLength = sizeof($orderId);
$newOrderId = "";
for ($i = 0; $i < $orderIdLength; ++$i) {
    $newOrderId .= $orderId[$i] . $time[$i];
}
$newOrderId = (int)$newOrderId;

Итак, если ваш фактический идентификатор заказа равен 489, а текущая временная метка - 1300778794, вы в конечном итоге получите идентификатор заказа, который выглядит как 418390. Если ваш клиент затем использует этот идентификатор заказа для чего-либо, вам просто нужно его сломать обратно вниз:

$newOrderId = explode("", (string)$newOrderId);
$length = sizeof($newOrderId);
$oldOrderId = "";
for ($i = 0; $i < $length; $i = $i + 2) {
    $oldOrderId .= $newOrderId[$i];
}
$oldOrderId = (int)$oldOrderId;

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

Редактировать: так же быстро, вы можете использовать другой метод генерации некоторого полуслучайного числа для дополнения идентификатора, отличного от time(). Например, вы можете сделать rand(pow(10, log10($orderId)), pow(10, log10($orderId)+1)), который всегда будет возвращать какое-то случайное число такой же длины, как и orderId.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...