Русский
Русский
English
Статистика
Реклама

Requests

Скрапинг avito без headless-браузера

18.01.2021 22:06:54 | Автор: admin

Недавно на хабре вышла статья Скрапинг современных веб-сайтов без headless-браузеров, и в комментариях было высказано мнение, что без headless-браузера не выйдет получить номер телефона из объявления на "авито" или "юле". Хочу это опровергнуть, ниже скрипт на python размером менее 100 строк кода, который успешно парсит "авито"

Я не являюсь специалистом по "парсингу" сайтов и это не моя работа, но не редки случаи, когда для решения моих рабочих, и не только задач, приходится это делать. Например необходимо получить баланс лицевого счета в каком-то сервисе(мобильные операторы), который не имеет для этого API или, что совсем печально, список доменов у регистратора (ещё один), который так-же не имеет API.

Как и в статье, пара комментариев из которой побудили меня написать этот пост, я тоже использую Python и библиотеку requests. Если не удается найти "внутренний" API , то приходится подключать библиотеку BeautifulSoup. Но тут всё оказалось намного проще.

Если открыть "полную" версию сайта https://avito.ru, и попытаться скопировать номер телефона, то станет понятно, что номер телефона на сайте не написан, а нарисован. Но в мобильной версии сайта, номер отдается текстом. Это можно проверить, если в инструментах разработчика в браузере посмотреть ответы при нажатии на кнопку "Позвонить".

Я не буду детально разбирать свой скрипт, в коде достаточно комментариев, чтоб понять что и на каком этапе происходит. Если кратко, то используется мобильная версия сайта, объявляются переменные для поиска по сайту а так-же две переменные "key" и "cookie", о них далее подробнее, потом идет процесс получения куки путем открытия главной страницы, далее запускается цикл, которые собирает id всех объявлений проходя по всем страницам. После того, как получены все объявления вторым циклом проходим по ним и получаем интересующую нас информацию.

Скриншот работы скрипта:

Всё так легко выглядит, т.к. были найдены нужные API. По сути данный скрипт похож на такой-же будь в нем применены официальные API. Я старался не добавлять функции и не проверять ответы на корректность или обрабатывать исключения, это ведь демонстрация метода, а не боевой инструмент. На мой взгляд так понятнее. Хотя несколько проверок и обработок там всё-же есть. Так-же я старался уместить скрипт в 100 строк кода.

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

Если будет интересно, я подробнее расскажу, как я искал API или могу подобный пример написать и для "юла".

Сам скрипт

Подробнее..
Категории: Scraping , Python , Api , Web , Python3 , Requests

Подключение к session в Java и Python. HttpURLConnection и CookieManager (Java). Requests(Python)

29.06.2020 22:07:32 | Автор: admin
Допустим, что нам надо подключиться к серверу, авторизоваться и поддерживать сессию. В браузере это выглядит следующим образом:
  1. На адрес http://localhost:8080/login отправляется пустой GET запрос.
  2. Сервер присылает формочку для заполнения логина и пароля, а также присылает Cookie вида JSESSIONID=094BC0A489335CF8EE58C8E7846FE49B.
  3. Заполнив логин и пароль, на сервер отправляется POST запрос с полученной ранее Cookie, со строкой в выходном потоке username=Fox&password=123. В Headers дополнительно указывается Content-Type: application/x-www-form-urlencoded.
  4. В ответ сервер нам присылает новую cookie c новым JSESSIONID=. Сразу же происходит переадресация на http://localhost:8080/ путём GET запроса с новой Cookie.
  5. Далее можно спокойно использовать остальное API сервера, передавая последнее Cookie в каждом запросе.


Рассмотрим, как это можно реализовать на Java и на Python.



Содержание:




Реализация на Python. Requests.



При выборе библиотеки для работы с сетью на Python большинство сайтов будет вам рекомендовать библиотеку requests , которая полностью оправдывает свой лозунг:
HTTP for Humans

Вся задача решается следующим скриптом:
import requestssession = requests.session()  #создаём сессиюurl = "http://localhost:8080/login"session.get(url)   #получаем cookiedata = {"username": "Fox", "password": "123"} response = session.post(url, data=data) #логинимся


Заметим, что махинации с Cookie и переадресацией происходят под капотом, прямо как в браузере. Так же можно отметить, что если завести ещё одну переменную session2, то можно держать активными сразу два подключения.

Реализация на Java, HttpURLConnection и CookieManager.



Поиски библиотеки для работы с сетью на Java приводят сразу к нескольким библиотекам. Например, java.net, Apache HttpClient и OkHttp3.

Я остановился на HttpURLConnection (java.net). Плюсами данной библиотеки является то, что это библиотека "из-под коробки", а так же, если надо написать приложение под android, на официальном сайте есть документация. Минусом является очень большой объём кода. (После Python это просто боль).

Итак, начнём. По документации для работы с сессиями можно использовать CookieManager:

CookieManager cookieManager = new CookieManager(null, CookiePolicy.ACCEPT_ALL);CookieHandler.setDefault(cookieManager);


Что нужно отметить, используя такой подход:
  • CookiePolicy.ACCEPT_ALL указывает, что надо работать со всеми cookie.
  • Переменная cookieManager далее нигде не будет использоваться. Она контролирует все подключения, и, если необходимо поддерживать несколько активных сессий, необходимо будет в этой одной переменной руками менять Cookie


Учтя это, можно записать и в одну строчку:
 CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));


Пункт 1 и 2. Выполним GET запрос для получения первой Cookie
URL url = new URL("http://localhost:8080/login");HttpURLConnection con = (HttpURLConnection) url.openConnection();con.setRequestMethod("GET");BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));String inputLine;final StringBuilder content = new StringBuilder();while ((inputLine = in.readLine()) != null) {    content.append(inputLine);}


После этого наш cookieManager будет содержать Cookie с сервера и автоматически подставит её в следующий запрос.

Веселье начинается с POST запросом.
url = new URL("http://localhost:8080/login");con = (HttpURLConnection) url.openConnection();con.setRequestMethod("POST");


Нужно записать в Headers Content-Type: application/x-www-form-urlencoded.
Почему метод называется setRequestProperty, а не setHeaders (или addHeaders) при наличии метода getHeaderField, остаётся загадкой.
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");


Далее идёт код, который непонятно по каким причинам не засунут под капот библиотеки.
con.setDoOutput(true);

Нужна эта строчка кода для открытия исходящего потока. Забавно, что без этой строки мы получим следующее сообщение:
Exception in thread main java.net.ProtocolException: cannot write to a URLConnection if doOutput=false call setDoOutput(true)

Открываем исходящий поток и записываем туда логин и пароль:
final DataOutputStream out = new DataOutputStream(con.getOutputStream());out.writeBytes("username=Fox&password=123");out.flush();out.close();


Остаётся считать ответ с уже перенаправленного запроса.

Реализация на Java, HttpURLConnection без CookieManager.



Можно реализовать и без CookieManager и самому контролировать перемещение cookie.
Пункт 1 и 2. Вынимаем cookie.
URL url = new URL("http://localhost:8080/login");HttpURLConnection con = (HttpURLConnection) url.openConnection();con.setRequestMethod("GET");BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));String inputLine;final StringBuilder content = new StringBuilder();while ((inputLine = in.readLine()) != null) {    content.append(inputLine);String cookie = con.getHeaderField("Set-Cookie").split(";")[0];}


Далее отправляем POST запрос, только на этот раз вставив cookie и отключив автоматическое перенаправление, т.к. перед ним надо успеть вытащить новое cookie:

// создаём запросurl = new URL("http://localhost:8080/login");con = (HttpURLConnection) url.openConnection();con.setRequestMethod("POST");//указываем headers и cookiecon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");con.setRequestProperty("Cookie", cookie);//отключаем переадресациюcon.setInstanceFollowRedirects(false);//отправляем логин и парольcon.setDoOutput(true);final DataOutputStream out = new DataOutputStream(con.getOutputStream());out.writeBytes("username=Fox&password=123");out.flush();out.close();//считываем и получаем второе cookieBufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));String inputLine;final StringBuilder content = new StringBuilder();while ((inputLine = in.readLine()) != null) {    content.append(inputLine);String cookie2 = con.getHeaderField("Set-Cookie").split(";")[0];


Далее во все запросы просто добавляем следующую строку:
con.setRequestProperty("Cookie", cookie2);


Надеюсь было полезно. В комментариях приветствуются варианты попроще.
Подробнее..

Облегчаем себе жизнь с помощью BeautifulSoup4

01.03.2021 16:18:41 | Автор: admin
Приветствую всех. В этой статье мы сделаем жизнь чуточку легче, написав легкий парсер сайта на python, разберемся с возникшими проблемами и узнаем все муки пайтона что-то новое.

Статья ориентирована на новичков, таких же как и я.

Начало


Для начала разберем задачу. Взял я малоизвестный сайт новостей об Израиле, так как сам проживаю в этой стране, и хочется читать новости без рекламы и не интересных новостей. И так, имеется сайт, на котором постятся новости: есть новости помеченные красным, а есть обычные. Те что обычные не представляют собой ничего интересного, а отмеченные красным являются самым соком. Рассмотрим наш сайт.



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



Как видите, сервер отдал нам красивый контейнер новостей (которых, кстати, больше чем на основном сайте, что нам на руку) без рекламы и мусора.

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



Как видим каждая новость лежит по-отдельности в тэге 'a' и имеет класс 'lenta'. Если мы откроем тэг 'a', то заметим, что внутри есть тэг 'span', в котором находится класс 'time2', либо 'time2 time3', а также время публикации и после закрытия тэга мы наблюдаем сам текст новости.

Что отличает важную новость от неважной? Тот самый класс 'time2' или 'time2 time3'. Новости помеченые 'time2 time3' и являются нашими красными новостями. Раз уж суть задачи понятна, перейдем к практике.

Практика


Для работы с парсерами умные люди придумали библиотеку BeautifulSoup4, в которой есть еще очень много крутых и полезных функций, но об этом в следующий раз. Нам также понадобиться библиотека Requests позволяющая отправлять различные http-запросы. Идем их скачивать.

(убедитесь, что стоит последняя версия pip)

pip install beautifulsoup4 

pip install requests

Переходим в редактор кода и импортируем наши библиотеки:

from bs4 import BeautifulSoupimport requests

Для начала сохраним наш URL в переменную:

url = 'http://mignews.com/mobile'

Теперь отправим GET()-запрос на сайт и сохраним полученное в переменную 'page':

page = requests.get(url)

Проверим подключение:

print(page.status_code)

Код вернул нам статус код '200', значит это, что мы успешно подключены и все в полном порядке.

Теперь создадим два списка (позже я объясню для чего они нужны):

new_news = []news = []

Самое время воспользоваться BeautifulSoup4 и скормить ему наш page, указав в кавычках как он нам поможет 'html.parcer':

soup = BeautifulSoup(page.text, "html.parser")

Если попросить его показать, что он там сохранил:

print(soup)

Нам вылезет весь html-код нашей страницы.

Теперь воспользуемся функцией поиска в BeautifulSoup4:

news = soup.findAll('a', class_='lenta')

Давайте разберём поподробнее, что мы тут написали.

В ранее созданный список 'news' (к которому я обещал вернуться), сохраняем все с тэгом 'а' и классом 'news'. Если попросим вывести в консоль все, что он нашел, он покажет нам все новости, что были на странице:



Как видите, вместе с текстом новостей вывелись теги 'a', 'span', классы 'lenta' и 'time2', а также 'time2 time3', в общем все, что он нашел по нашим пожеланиям.

Продолжим:

for i in range(len(news)):    if news[i].find('span', class_='time2 time3') is not None:        new_news.append(news[i].text)

Тут мы в цикле for перебираем весь наш список новостей. Если в новости под индексом [i] мы находим тэг 'span' и класc 'time2 time3', то сохраняем текст из этой новости в новый список 'new_news'.

Обратите внимание, что мы используем '.text', чтобы переформатировать строки в нашем списке из 'bs4.element.ResultSet', который использует BeautifulSoup для своих поисков, в обычный текст.

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

Выведем наши данные:

for i in range(len(new_news)):    print(new_news[i])

Вот что мы получаем:



Мы получаем время публикации и лишь интересные новости.

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

Надеюсь эта статья поможет новичкам понять, что можно делать с помощью парсеров и поможет им немного продвинуться вперед с обучением.

Спасибо за внимание, был рад поделиться опытом.
Подробнее..

Создаём мини PHP SDK для подписи запросов к Oracle Cloud Infrastructure API

11.02.2021 04:19:49 | Автор: admin

Идея написать эту библиотеку возникла, когда захотелось в полной мере воспользоваться всеми преимуществамибесплатного предложенияOracle Cloud Infrastructure, а именно 10 ГБ хранилища объектов (Object Storage) и 10 ТБ исходящего трафика в месяц. Разница сAWSS3 простоогромнейшая. К сожалению,OracleCloudне имеетв наличииSDKдля всё еще самого популярного языка программирования для разработки веб-сайтов. Хорошая новость состоит в том, что сервисчастично совместимсAmazonS3, а это означает, что можно применить уже имеющиеся и отлично задокументированныеинструменты разработчика, в том числе дляPHP.

Тем, кому не терпится увидеть код, добро пожаловатьhttps://github.com/hitrov/oci-api-php-request-sign.

Действительно, с имеющимися инструментами можно выполнять почти все операции, которые можно представить - для создания, чтения и удаления корзин (buckets) и объектов (файлов). Корзины могут быть как публичными (с возможностью листинга файлов и без) и приватными. Есть возможность загружать файлы в приватную корзину, имея лишь секретныйURL(сгенерированный вручную с помощьюCLIили веб-интерфейса - консолиOracleCloud). На самом деле этого уже может быть достаточно для многих сценариев, особенно если генерировать стойкие к подбору имена файлов - в случае, если вы не хотите выставлять их на публику.

Меня интересовала возможность расшаривать файлы, то есть делиться общедоступными ссылками на файлы, и, конечно же, ограничивать доступ при необходимости. При небольшом количестве файлов можно делать это вручную, но мы собрались здесь, чтобы иметь программный доступ. ВAWS S3этоназываетсяPre-Signed URL,ауOracle -Pre-Authenticated Request.

Установка AWS PHP SDK

composer require aws/aws-sdk-php

Ниже будет показано, где взять доступы (AWS_ACCESS_KEY_IDи AWS_SECRET_ACCESS_KEY.

Namespace же можно увидеть

$namespaceName = 'frpegp***';$bucketName = 'test******05';$region = 'eu-frankfurt-1';$endpoint = "https://$namespaceName.compat.objectstorage.$region.oraclecloud.com";$s3 = new Aws\S3\S3Client([    'version' => 'latest',    'region'  => $region,    'endpoint' => $endpoint,    'signature_version' => 'v4',    'use_path_style_endpoint' => true,    'credentials' => [        'key'    => 'AKI***YYJ', // remove if you have env var AWS_ACCESS_KEY_ID        'secret' => 'ndK***cIf', , // remove if you have env var AWS_SECRET_ACCESS_KEY    ],]);$cmd = $s3->getCommand('GetObject', [    'Bucket' => $bucketName,    'Key' => 'fff.txt']);$request = $s3->createPresignedRequest($cmd, '+20 minutes');

К сожалению, данная операция, хотя и не вызывает ошибку, отдавая в ответPSR-7request, но возвращаемый имURLвида

https://{namespace}.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/{bucket}/fff.txt?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=***%2F20210210%2Feu-frankfurt-1%2Fs3%2Faws4_request&X-Amz-Date=20210210T185244Z&X-Amz-SignedHeaders=host&X-Amz-Expires=1200&X-Amz-Signature=a167a***9a857

просто не работает.

<?xml version="1.0" encoding="UTF-8"?><Error>    <Message>The required information to complete authentication was not provided.</Message>    <Code>SignatureDoesNotMatch</Code></Error>

Поскольку совместимость для данной операции не была заявлена, странно было бы ожидать иного, но попробовать стоило :)

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

Разумеется, подпись будет работать для всех запросов начиная от создания\остановки\бэкапаавтономной базы данных, управленияDNSи заканчивая отправкойEmail. Всё что указано в API Reference and Endpoints.

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

Действия в профиле Oracle CloudДействия в профиле Oracle Cloud

API KeysAdd API Key

API Keys - Add API KeyAPI Keys - Add API Key

Downloadprivatekey(сохраняем в надежном месте), затемAdd

Download Private Key and AddDownload Private Key and Add

Сохраняем все значения из текстового поля, они нам понадобятся через минуту

Configuration File exampleConfiguration File example

Для того, чтобы воспользоваться AWS PHP SDK, вам необходимы Customer Secret Keys (они же AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY в понимании Amazon.

Установка Oracle Cloud Infrastructure mini PHP SDK(никаких внешних зависимостей!)

composer require hitrov/oci-api-php-request-sign

Пакет использует стандартнуюPSR-4 автозагрузку классов.

require 'vendor/autoload.php';use Hitrov\OCI\Signer;

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

OCI_TENANCY_ID=ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsqOCI_USER_ID=ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjqOCI_KEY_FINGERPRINT=20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34OCI_PRIVATE_KEY_FILENAME=/path/to/privatekey.pem

В этом случае конструктор не принимает аргументов.

$signer = new Signer;

Переменным среды есть несколько альтернативhttps://github.com/hitrov/oci-api-php-request-sign#alternatives-for-providing-credentials, не стану дублировать это здесь.

МыпопробуемвыполнитьCreatePreauthenticatedRequest.

Вся сложность (если можно так выразиться) абстрагирована в один публичный метод

public function getHeaders(    string $url, string $method = 'GET', ?string $body = null, ?string $contentType = 'application/json', string $dateString = null): array

Пример использования

$curl = curl_init();$url = 'https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/{namespaceName}/b/{bucketName}/p/';$method = 'POST';$body = '{"accessType": "ObjectRead", "name": "read-access-to-image.png", "objectName": "path/to/image.png", "timeExpires": "2021-03-01T00:00:00-00:00"}';$headers = $signer->getHeaders($url, $method, $body, 'application/json');var_dump($headers);$curlOptions = [  CURLOPT_URL => $url,  CURLOPT_RETURNTRANSFER => true,  CURLOPT_ENCODING => '',  CURLOPT_MAXREDIRS => 10,  CURLOPT_TIMEOUT => 5,  CURLOPT_FOLLOWLOCATION => true,  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,  CURLOPT_CUSTOMREQUEST => $method,  CURLOPT_HTTPHEADER => $headers,];if ($body) {  // not needed for GET or HEAD requests  $curlOptions[CURLOPT_POSTFIELDS] = $body;}curl_setopt_array($curl, $curlOptions);$response = curl_exec($curl);echo $response;curl_close($curl);
array(6) {  [0]=>  string(35) "date: Mon, 08 Feb 2021 20:49:22 GMT"  [1]=>  string(50) "host: objectstorage.eu-frankfurt-1.oraclecloud.com"  [2]=>  string(18) "content-length: 76"  [3]=>  string(30) "content-type: application/json"  [4]=>  string(62) "x-content-sha256: X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE="  [5]=>  string(538) "Authorization: Signature version=\"1\",keyId=\"ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34\",algorithm=\"rsa-sha256\",headers=\"date (request-target) host content-length content-type x-content-sha256\",signature=\"LXWXDA8VmXXc1NRbMmXtW61IS97DfIOMAnlj+Gm+oBPNc2svXYdhcXNJ+oFPoi9qJHLnoUiHqotTzuVPXSG5iyXzFntvkAn3lFIAja52iwwwcJflEIXj/b39eG2dCsOTmmUJguut0FsLhCRSX0eylTSLgxTFGoQi7K/m18nafso=\""}
{  "accessUri": "/p/AlIlOEsMok7oE7YkN30KJUDjDKQjk493BKbuM-ANUNGdBBAHzHT_5lFlzYC9CQiA/n/{namespaceName}/b/{bucketName}/o/path/to/image.png",  "id": "oHJQWGxpD+2PhDqtoewvLCf8/lYNlaIpbZHYx+mBryAad/q0LnFy37Me/quKhxEi:path/to/image.png",  "name": "read-access-to-image.png",  "accessType": "ObjectRead",  "objectName": "path/to/image.png",  "timeCreated": "2021-02-09T11:52:45.053Z",  "timeExpires": "2021-03-01T00:00:00Z"}

Вот и всё!

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

1) Прежде всего, нам необходимо собрать список подписываемых заголовков (SIGNING_HEADERS_NAMES). Он всегда содержит

  • date

  • (request-target)

  • host

ДляPOST|PUT|PATCHзапросов добавляются еще три

  • content-length

  • content-type

  • x-content-sha256

$signingHeadersNames = $signer->getSigningHeadersNames('POST');

2) SHA256 хэш тела запроса кодированный вbase64

$bodyHashBase64 = $signer->getBodyHashBase64($body);

3) Сформировать строку для подписи, в нашем случае она будет выглядеть следующим образом

date: Mon, 08 Feb 2021 20:51:33 GMT(request-target): post /n/{namespaceName}/b/{bucketName}/p/host: objectstorage.eu-frankfurt-1.oraclecloud.comcontent-length: 76content-type: application/jsonx-content-sha256: X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
$signingString = $signer->getSigningString($url, $method, $body, 'application/json');

Хэш мы получили в (2).Важно, что дата и время не должны отличаться от текущих на более, чем 5 минут.

4) Подписать строку из (3) приватным ключом с помощью алгоритмаRSA-SHA256

$signature = $signer->calculateSignature($signingString, $privateKeyString);

5) Сформировать KEY_ID данными, которые вы скопировали при создании API Key, это строка, разделенная слешами

"{OCITENANCYID}/{OCIUSERID}/{OCIKEY_FINGERPRINT}"

$keyId = $signer->getKeyId();

6) Теперь мы готовы сгенерировать заголовок авторизации(версия 1останется таковой до отдельного уведомления отOracle)

Authorization: Signature version=\"1\",keyId=\"{KEY_ID}\",algorithm=\"rsa-sha256\",headers=\"{SIGNING_HEADERS_NAMES_STRING}\",signature=\"{SIGNATURE}\"

гдеSIGNING_HEADERS_NAMES_STRING это список из (1), разделенный пробелами.

date (request-target) host content-length content-type x-content-sha256

$signingHeadersNamesString = implode(' ', $signingHeadersNames);$authorizationHeader = $signer->getAuthorizationHeader($keyId, $signingHeadersNamesString, $signature);

Пример вывода

Authorization: Signature version=\"1\",keyId=\"ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34\",algorithm=\"rsa-sha256\",headers=\"date (request-target) host content-length content-type x-content-sha256\",signature=\"LXWXDA8VmXXc1NRbMmXtW61IS97DfIOMAnlj+Gm+oBPNc2svXYdhcXNJ+oFPoi9qJHLnoUiHqotTzuVPXSG5iyXzFntvkAn3lFIAja52iwwwcJflEIXj/b39eG2dCsOTmmUJguut0FsLhCRSX0eylTSLgxTFGoQi7K/m18nafso=\"

Реальные заголовки запроса - см. выводvar_dump()выше - должны содержать всё из (3), за исключением поля(request-target)и его значения. И, конечно же, заголовок авторизации (6).

МнепомогластатьяOracle Cloud Infrastructure (OCI) REST call walkthrough with curl. Некоторые имена методов позаимствованы из официальногоGoLangSDK. Тест-кейсы оттуда же.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru