RuStore. url для получения токена авторизации

В инструкции по работе с API RuStore указаны параметры взаимодействия для получения токена авторизации, https://help.rustore.ru/rustore/for_developers/worki_with_RuStore_API/authorization_token_RuStore_API

По данной инструкции есть два вопроса:

1 не указано на какой url нужно отправлять POST запрос введите сюда описание изображения

2 что значит "Только для запросов, подписанных приватным ключом, публичная часть которого загружена соответствующим владельцем в систему RuStore Консоль" ? введите сюда описание изображения

(в системе зарегистрирован, заявление на монетизацию подписано с помощью ЭЦП и получен статус "одобрено". Приватный ключ в личном кабинете сгенерирован).

Ответ техподдержки: введите сюда описание изображения

Кто-нибудь проходил этот "квест" до конца ? )


Ответы (6 шт):

Автор решения: PHP Ninja

После продолжительной переписки с поддержкой (номер тикета запроса [VKS-19386]) найден правильный ответ.

<?PHP
//https://help.rustore.ru/rustore/for_developers/worki_with_RuStore_API/authorization_token_RuStore_API

$tnow = time();
$company_id = 1234567890;//id компании в магазине rustore
$year_month_day = date("Y-m-d");
$hour_minute_seconds = date("H:i:s");

$clock_belt = '+03:00';//на странице поддержки указан часовой пояс +3
//на нашем сервере часовой пояс тоже +3. У Вас может быть другой.

//собираем строку которую будем подписывать
$string_to_sign = $company_id;

$times = $year_month_day;
$times .= 'T';
$times .= $hour_minute_seconds;
$times .= $clock_belt;

$string_to_sign .= $times;
//получаем строку формата 2023-07-08T13:24:41+03:00

//private_key сгенерированный в личном кабинете магазина rustore.
$private_key = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgАБВГД
-----END RSA PRIVATE KEY-----
EOD;

//все доступные методы подписи заносим в массив
$Array_allowed_crypt_method = openssl_get_md_methods(true);

//выбираем метод шифрования
//var_dump($Array_allowed_crypt_method);

//var_dump($Array_allowed_crypt_method[48]);//"sha512WithRSAEncryption"
//этот метод подписи соответствует указанному в RuStore SHA512withRSA, //но на разных серверах номер этого метода может отличаться (у нас это [48]); 
//При неверно выбранном методе формирования подписи сервер RuStore будет выдавать ошибку "signature_encode_error"!

$algo = $Array_allowed_crypt_method[48];//"sha512WithRSAEncryption"


//формируем подпись
$make_signature = openssl_sign($string_to_sign, $binary_signature, $private_key, $algo);//
if($make_signature < 1)
{
    echo "ошибка при формировании подписи";
    die();
}



//подпись $binary_signature содержит символы  не входящие в кодировку UTF-8;
//$binary_signature невозможно конвертировать в JSON для передачи в body
//конвертируем $binary_signature в base64
$signature_64 = base64_encode($binary_signature);


//POST запрос в магазин//
$url = 'https://public-api.rustore.ru/public/auth';


//вариант сборки JSON из массива для тела запроса
$Array_body = Array();
$Array_body['companyId'] = "$company_id";
$Array_body['timestamp'] = "$times";
$Array_body['signature'] = $signature_64;//

$JSON_for_body = json_encode($Array_body);

//echo "Есть ли ошибка при формировании JSON ? \n";
//print_r(json_last_error_msg());


//опции потока запроса
$options = array('http' =>
  array(
    'method'  => 'POST',
    'header'  => "Content-Type: application/json\r\n".
                "Accept: application/json\r\n",
    'content' => $JSON_for_body,
    'timeout' => 60,
    'ignore_errors' => true
        )
);
// ! опция 'ignore_errors' => true нужна чтоб увидеть ответ сервера RuStore если Error_Code не 200.


//формируем поток с опциями
$context  = stream_context_create($options);

//выполняем запрос
$otvet = file_get_contents($url, false, $context, -1, 40000);

$otvet = json_decode($otvet);
var_dump($otvet);
?>
→ Ссылка
Автор решения: Денис Жигалов

Написал модуль Rustore Api на C#. Вот ссылка на github https://github.com/deniszhigalov/rustore-api. Можно установить пакет с nuget.org https://www.nuget.org/packages/RustoreApi/

→ Ссылка
Автор решения: PHP Ninja

Следующий этап работы с API - получения от сервера RuStore данных платежа клиента по subscription_token. Справка описана здесь https://help.rustore.ru/rustore/for_developers/worki_with_RuStore_API/public_api_1 введите сюда описание изображения

но не указан URL на который нужно направлять запрос GET /public/purchases/{subscription_token}

Правильный URL https://pay-backapi.rustore.ru/public/purchases/{subscription_token}

Может поможет кому-нибудь )

→ Ссылка
Автор решения: Дмитрий Волков

Может быть кому-то потребуется код для получения подписи на python (слегка измененный вариант, полученный от разработчиков VKS-27749). Для корректной работы нужно подключить модуль pycryptodome

import base64
import json
from datetime import datetime
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA512
from Crypto.PublicKey import RSA

secret_private = b'MIIEvgIBADANBgk'  # сюда занести сгенерированный в консоли privatekey
company_id = "тут идентификатор компании, полученный из консоли rustore"

def generate():
    key = RSA.import_key(base64.b64decode(secret_private))
    # формируем строку для подписи
    sdt = datetime.now().isoformat()+"+03:00"
    to_sign = company_id + sdt
    print("Get hash from: " + to_sign)

    # формируем хеш
    hash = SHA512.new(to_sign.encode())

    # формируем подпись
    binary_signature = pkcs1_15.new(key).sign(hash)
    signature = base64.b64encode(binary_signature).decode('utf-8')
    print("SIGN: " + signature)

    # формируем результат в формате JSON
    result = {
        "companyId": company_id,
        "timestamp": sdt,
        "signature": signature
    }

    return json.dumps(result)

→ Ссылка
Автор решения: Арсений Воробьёв

Реализация авторизации на typescript. Сохраню для тех, кто придет сюда с этим вопросом)

import * as moment from 'moment';
import { createSign } from 'node:crypto';
import axios from 'axios';

const API_URL = 'https://public-api.rustore.ru';
enum Path {
  Auth = '/public/auth/',
}

export class RSAuth {
  private readonly privateKey: string =
    '-----BEGIN PRIVATE KEY-----\n' +
    'MIIEvgIBADANBgkq...\n' +
    '-----END PRIVATE KEY-----';
  private readonly companyId = 123;

  // constructor() {} // private readonly companyId: string, // private readonly privateKey: string,

  public async auth() {
    const dateStr = moment().format();

    const str = `${this.companyId}${dateStr}`;

    const sign = createSign('RSA-SHA512');
    sign.write(str);
    sign.end();
    const signature = sign.sign(this.privateKey, 'base64');

    console.log('Sign: ', signature);

    try {
      const result = await axios.post(`${API_URL}${Path.Auth}`, {
        timestamp: dateStr,
        companyId: this.companyId,
        signature,
      });
      console.log('result :>> ', result);
    } catch (e) {
      console.log(e);
    }
  }
}

→ Ссылка
Автор решения: IAS

Внесу свой вклад, вот мой код для получение токена под Laravel.

    $companyId = env('RU_STORE_COMPANY_ID'); // Код компании в RuStore
    $time = now()->toIso8601String();
    $privateKey = file_get_contents(base_path(env('RU_STORE_PRIVATE_KEY'))); // Секретный ключ

    // Вместо openssl_get_md_methods, можно сразу использовать OPENSSL_ALGO_SHA512
    if (!openssl_sign($companyId . $time, $signatureBinary, $privateKey, OPENSSL_ALGO_SHA512)) {
        return sendResponse(__(''), false, 400);
    }

    // Формирование запроса через Illuminate\Support\Facades\Http
    $requestBody = [
        'companyId' => $companyId,
        'timestamp' => $time,
        'signature' => base64_encode($signatureBinary)
    ];
    $http = Http::withHeaders([
        'Content-Type' => 'application/json',
        'Accept' => 'application/json',
    ])
        ->timeout(60)
        ->post('https://public-api.rustore.ru/public/auth', $requestBody);
    $response = $http->json();
    
    // Выводим полученный результат
    dd($response);
→ Ссылка