401 Ошибка "oauth_problem = nonce_used" Добавление продуктов в Magento w/Rest API

Получение статуса 401 с возвратом сообщения "oauth_problem = nonce_used" при попытке добавить продукты в Magento, используя остальные api. Как ни странно, продукты по-прежнему импортируются, но это действительно отбрасывает меня, потому что я не возвращаю идентификатор продукта, чтобы обновлять информацию о запасе.

Magento install - совершенно новый (criticalwebhost installer) 1.7.0.2, а код, который я использую, в значительной степени скопирован и вставлен с сайта magento...

$callbackUrl = '****';
$temporaryCredentialsRequestUrl = "*****/oauth/initiate?oauth_callback=".urlencode($callbackUrl);
$adminAuthorizationUrl = '*****/admin/oauth_authorize';
$accessTokenRequestUrl = '*****/oauth/token';
$apiUrl = '*****/api/rest';

$consumerKey = '*****';
$consumerSecret = '******';

try
{
$authType = ($_SESSION['state'] == 2) ? OAUTH_AUTH_TYPE_AUTHORIZATION : OAUTH_AUTH_TYPE_URI;
$oauthClient = new OAuth($consumerKey, $consumerSecret, OAUTH_SIG_METHOD_HMACSHA1, $authType);
$oauthClient->enableDebug();

if(!isset($_GET['oauth_token']) && !$_SESSION['state'])
{
  $requestToken = $oauthClient->getRequestToken($temporaryCredentialsRequestUrl);
  $_SESSION['secret'] = $requestToken['oauth_token_secret'];
  $_SESSION['state'] = 1;
  header('Location: '.$adminAuthorizationUrl.'?oauth_token='.$requestToken['oauth_token']);
  exit;
} else if($_SESSION['state'] == 1)
{
  $oauthClient->setToken($_GET['oauth_token'], $_SESSION['secret']);
  $accessToken = $oauthClient->getAccessToken($accessTokenRequestUrl);
  $_SESSION['state'] = 2;
  $_SESSION['token'] = $accessToken['oauth_token'];
  $_SESSION['secret'] = $accessToken['oauth_token_secret'];
  header('Location: '.$callbackUrl);
  exit;
} else
{
  $oauthClient->setToken($_SESSION['token'], $_SESSION['secret']);
  $resourceUrl = "$apiUrl/products";


  $productData = json_encode(array(
'type_id' => 'simple',
    'attribute_set_id' => 4,
    'sku' => $local_product['sku'],
    'weight' => 1,
    'status' => 1,
'visibility' => 4,
    'name' => $local_product['name'],
    'description' => $local_product['description'],
    'short_description' => $local_product['description'],
    'price' => $local_product['price'],
    'tax_class_id' => 0,
  ));
  $headers = array('Content-Type' => 'application/json');
  $oauthClient->fetch($resourceUrl, $productData, OAUTH_HTTP_METHOD_POST, $headers);
  $respHeader = $oauthClient->getLastResponseHeaders();


}

} catch(OAuthException $e)
{
  print_r($e);
}
}

session_destroy();

Точная ошибка: { "messages": { "error": [{ "code": 401, "message": "oauth_problem = nonce_used" }]}}

Ответ 1

В Mage_Api2_Model_Resource, о строке 227, найдите

$this->getResponse()->setHeader('Location', $newItemLocation);

и вставьте сразу после этого:

 $this->getResponse()->setHttpResponseCode(202); 

Ссылка: Википедия "Местоположение HTTP":

Поле заголовка HTTP-местоположения возвращается в ответах HTTP сервер при двух обстоятельствах:

  • Попросить веб-браузер загрузить другую веб-страницу. В этом обстоятельство, заголовок местоположения должен быть отправлен с статусом HTTP код 3хх.
  • Чтобы предоставить информацию о местоположении нового созданный ресурс. В этом случае заголовок местоположения должен отправляться с кодом состояния HTTP 201 или 202

Ответ 2

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

Ответ 3

Я смотрел на это и из того, что я вижу в коде, похоже, OAuth регистрирует все ваши вызовы, и если он обнаруживает, что тот же самый nonce был фактически использован с тем же самым timestamp как предыдущий вызов, он просто отбросит его с помощью этой конкретной ошибки oauth_problem = nonce_used.

Код от app/code/core/Mage/Oauth/Model/Server.php

/**
 * Validate nonce request data
 *
 * @param string $nonce Nonce string
 * @param string|int $timestamp UNIX Timestamp
 */
protected function _validateNonce($nonce, $timestamp)
{
    $timestamp = (int) $timestamp;

    if ($timestamp <= 0 || $timestamp > (time() + self::TIME_DEVIATION)) {
        $this->_throwException('', self::ERR_TIMESTAMP_REFUSED);
    }
    /** @var $nonceObj Mage_Oauth_Model_Nonce */
    $nonceObj = Mage::getModel('oauth/nonce');

    $nonceObj->load($nonce, 'nonce');

    if ($nonceObj->getTimestamp() == $timestamp) {
        $this->_throwException('', self::ERR_NONCE_USED);
    }
    $nonceObj->setNonce($nonce)
        ->setTimestamp($timestamp)
        ->save();
}

Таким образом, я бы сказал, что когда вы делаете вызовы через Magento API в REST, вы должны проявлять особую осторожность, чтобы каждый сделанный вами запрос имел свое собственное уникальное значение timestamp/nonce combinaison.

Также см.

oauth_nonce. Случайное значение, уникально созданное приложением.
oauth_timestamp. Положительное целое число, выраженное в секундах с 1 января 1970 года 00:00:00 GMT.

и

nonce_used: комбинация nonce-timestamp уже используется.

Из этого источника: http://devdocs.magento.com/guides/v2.0/get-started/authentication/gs-authentication-oauth.html

Ответ 4

У меня была такая же проблема, и для ее решения я посмотрел модуль mod_rewrite apache и включил ведение журнала для этого модуля, который был добавлен в файл apache httpd.conf(это для apache 2.4x, 2.2x нужно делать по-другому.

<IfModule mod_rewrite.c>
   LogLevel mod_rewrite.c:trace8
</IfModule>

Ошибки затем выходят в стандартную версию apache error_log Когда я посмотрел на переписывание здесь, я мог видеть, что мой запрос на отправку был дважды перезаписан, первый раз, когда он добавляет продукты в magento, и во второй раз он не смог добавить продукт снова, поскольку, конечно, используется nonce.

Я мог видеть, что правило перезаписи, которое вызывало это в .htaccess, было тем, что

## workaround for HTTP authorization
## in CGI environment

  RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 

Я проверяю свою конфигурацию, и я действительно запускал быстрый cgi php, и я проверил это, проверив значение API Сервера из php info script. Я так долго пробовал это решить, что, зная первопричину, я просто изменил PHP с CGI php на модуль apache, и, прежде чем мой запрос на отправку теперь перезаписывается только один раз, и возвращает этот код ответа на все неуловимые 200.

Ответ 5

Работа вокруг:

Используйте SOAP API.

Причина, по которой она не используется раньше:

SOAP API не предоставил возможности для настраиваемых атрибутов продукта или полей прироста количества продукта.

Fix:

Добавьте любое поле, которое вы хотите использовать, используя SOAP api, сначала создав для них массив объектов (последние 4 строки кода, повторяющиеся для каждого добавленного поля):

$additionalAttrs = array();

$per_item = new stdClass();
$per_item->key = 'price_per_item';
$per_item->value = $local_product['price'];
$additionalAttrs['single_data'][] = $per_item;

И затем добавив его в ваш массив продуктов с ключом "дополнительные_трибуты", например:

'additional_attributes' => $additionalAttrs,

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