Для решения этой проблемы нужно пройти в админке в Система-Пользователи-API
, зайти в нужный объект списка и добавить свой IP адрес в список.
Либо на странице, с сообщением о проблеме с API просто нажать на кнопку Добавить IP-адрес
и обновить страницу.
Но у нашего клиента на OpenCart 2.3 было не все так просто ...
Перед началом разработки модуля клиент сообщил мне, что в админке на странице редактирования заказа у него часто/рандомно не работает изменение заказа: У вас нет разрешения на доступ к API!
А как позже выяснилось, такая проблема у клиента на 2 сайтах, где используется одна и та же версия OpenCart 2.3, сайты размещены у одного и того же хостера.
Изначально я не придал этому значения, так как проблема у клиента была до меня, а сроки по разработке были крайне сжатые (как обычно), а значит ее решение это второстепенная задача, однако на этапе внедрения модуля в интернет-магазин клиента начались проблемы.
Дело в том, что интерфейс функциональности разработанного мной модуля располагался на странице редактирования заказа, во вкладке Товары
, а из-за проблем доступа к API клиент не мог проверить работу модуля. Но это была первая часть проблемы. Как выяснилось позже мой модуль не мог корректно функционировать, так как использовал доступ к заказу основываясь на API.
Первым делом я перепроверил ajax запросы на корретность работы, как на клиенте так и на сервере. Токен на клиенте есть, проверка токена и авторизация по токену на сервере есть. Все также как и у API запросов, но не работает ...
В другой статье мы уже вкратце разбирали Ajax API, а теперь копнем глубже.
Посмотрим контроллер catalog/controller/api/login.php
(запрос получения токена для работы с API /index.php?route=api/login
), в случае валидного API key
и наличия в этой группе IP адреса выполняющего (того кто делает запрос), данный запрос стартует новую сессию с именем api
с единственным ключом api_id
:
php$session_id_new = $this->session->createId(); $this->session->start('api', $session_id_new); $this->session->data['api_id'] = $api_info['api_id'];
Затем посмотрим catalog/controller/startup/session.php
(это первичный контроллер, который запускается при любом запросе в catalog
, до основного контроллера), здесь при наличии токена полученного в предыдущем запросе происходит старт сессии с именем api
:
php$this->session->start('api', $query->row['session_id']);
А теперь пройдем в файл с классом сессии system/library/session.php
и смотрим метод start
:
phppublic function start($key = 'default', $value = '') { if ($value) { $this->session_id = $value; } elseif (isset($_COOKIE[$key])) { $this->session_id = $_COOKIE[$key]; } else { $this->session_id = $this->createId(); } if (!isset($_SESSION[$this->session_id])) { $_SESSION[$this->session_id] = array(); } $this->data = &$_SESSION[$this->session_id]; //... }
На основании предыдущих файлов можно сказать: session_id
может быть взят из куки api
, а данные сессии можно получить по session_id
.
Вспоминаем что API запросы OpenCart проверяют валидность доступа в catalog
контекст по токену следующим образом:
phpif (!isset($this->session->data['api_id'])) { $json['error']['warning'] = $this->language->get('error_permission'); } else { ... }
И приходим к понимаю того, что с сессией проблемы, хотя судя по коду должно быть все ровно.
Для того чтобы понять в чем проблема, можно попробовать записывать данные $_SESSION
в файл в запросе получения токена (после его получения), и при первом API запросе в файле catalog/controller/startup/session.php
прямо перед или после старта api
сессии.
В итоге я увидел что:
session_id
создается на этапе авторизации и в нее записывается один единственный ключ api_key
, но уже при следующем запросе к API, массив данных сессии с этим session_id
пуст, но заполняется при отработке всех контроллеров указанных в массиве action_pre_action
(в файле system/config/catalog.php
) и данные сессии сохраняются. Однако при этом в нем отсутствует ключ api_id
, без которого дальнейшая работа с API невозможна и поэтому мы видим сообщение: У вас нет разрешения на доступ к API!
Почему возникает данная проблема мне не удалось выяснить. Развернув точную копию сайта клиента у себя на локальном сервере, воспроизвести проблему не получилось.
После обращения клиента в ТП хостинга, проблема исчезла на некоторое время (в это же время я пытался решить ее самостоятельно, но безуспешно, ибо не воспроизводилось), а потом благополучно, примерно через сутки, проблема вернулась.
Повторный дебаг $_SESSION
не дал результатов, все также: при запросе авторизации создавалась новая сессия с ключом api_id
, а при следующем обращении к API эта новая сессия была пуста.
Понимая что данные сессии не могут сохранится в $_SESSION
при запросе авторизации снова смотрим catalog/controller/startup/session.php
и видим запрос к БД:
php$query = $this->db->query("SELECT DISTINCT * FROM `" . DB_PREFIX . "api` `a` LEFT JOIN `" . DB_PREFIX . "api_session` `as` ON (a.api_id = as.api_id) LEFT JOIN " . DB_PREFIX . "api_ip `ai` ON (as.api_id = ai.api_id) WHERE a.status = '1' AND as.token = '" . $this->db->escape($this->request->get['token']) . "' AND ai.ip = '" . $this->db->escape($this->request->server['REMOTE_ADDR']) . "'");
Если этот запрос возвращает не пустой массив, значит можно считать что авторизация прошла успешно, а среди выбранных из БД данных есть api_id
.
В catalog/controller/startup/session.php
сразу после старта сессии пишем:
phpif ($query->num_rows) { $this->session->start('api', $query->row['session_id']); //это может решить проблему с доступом по апи $this->session->data["api_id"] = $query->row["api_id"]; //... }
И проблема У вас нет разрешения на доступ к API! решена!!!
catalog/controller/startup/session.php
вставить в массив сессии ключ api_id
: $this->session->data["api_id"] = $query->row["api_id"];
Для убедительности я провел тест: получил ошибку У вас нет разрешения на доступ к API!, а затем применил описанное выше решение и не перезагружая страницы (где была ошибка) провел несколько ajax запросов к API OpenCart, которые прошли успешно.