Перейти к содержанию

Аутентификация


Регистрация в системе

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

  • Создать кассу, перейдя во вкладку "Кассы"
  • Обратиться к прикреплённому к вам специалисту для того, чтобы мы настроили вашу новую кассу и провели верификацию
  • После того, как касса будет настроена и верифицирована, вам необходимо сгенерировать ключи
  • Перейти во вкладку "API", найти созданную кассу и нажать на "Сгенерировать ключ"
  • В открывшейся модалке будет указано название кассы, URL вашего продукта и вам будет необходимо нажать на "Сгенерировать ключ"
  • Скопировать и сохранить значения из полей UUID и Private key
    • UUID - идентификатор вашей кассы. Он будет необходим при взаимодействии с нашим API;
    • Private key - приватный RSA ключ в PEM формате. Ключ будет вам необходим для создания цифровой подписи при взаимодействии с нашим API. Важная оговорка, данный ключ мы генерируем на клиентской стороне, т.е. в браузере. Мы не сохраняем данный ключ у себя, поэтому это безопасно. Мы сохраняем лишь публичный ключ, т.к. он нам необходим для проверки цифровой подписи в ваших запросах;
  • Передать отделу разработки/devops оба секрета (uuid и private key)

Аутентификация в API

HH использует следующие заголовки для аутентификации:

  • x-access-timestamp: timestamp запроса
  • x-access-merchant-id: идентификатор кассы. Получен при создании кассы и генерации ключей для неё. В примере кода ниже, этот заголовок указывается в переменной project_id
  • x-access-signature: конкатенация тела http запроса в Base64Url и timestamp'а, подписанная цифровой подписью от полученной строки, предварительно захешированные sha256: sha256(base64url(body) + str(timestamp))
  • x-access-token: Base64Url закодированный public key из RSA-SHA256 пары

Примеры кода

Пример кода на Python3

import base64  
import json  
import time  
import requests  

from Crypto.Hash import SHA256  
from Crypto.PublicKey import RSA  
from Crypto.Signature.pkcs1_15 import PKCS115_SigScheme  

url = "https://api.hh-processing.com/api/v1/payment/p2p/payin"  

# Идентификатор кассы. Получен при создании кассы и генерации ключей для неё  
project_id = "57aff4db-b45d-42bf-bc5f-b7a499a01782"  

# Путь до файла с приватным ключом, который вы получили в амдинке  
private_key_path = "./private.pem"  

payload = {  
    "general": {  
        "project_id": project_id  
    }  
}  


def parse_json(prefix, _obj, _result):  
    if isinstance(_obj, dict):  
        for key, value in _obj.items():  
            new_prefix = f"{prefix}:{key}" if prefix else key  
            parse_json(new_prefix, value, _result)  
    elif isinstance(_obj, list):  
        for index, item in enumerate(_obj):  
            new_prefix = f"{prefix}:{index}"  
            parse_json(new_prefix, item, _result)  
    else:  
        _result.append(f"{prefix}:{_obj or 'None'}")  


def normalize_message(_payload):  
    _result = []  
    parse_json('', _payload, _result)  
    _result.sort()  
    _joined_result = ";".join(_result)  
    return _joined_result  


with open(private_key_path, 'rb') as f:  
    private_key = RSA.importKey(f.read())  


public_key = private_key.public_key().export_key()  
api_key = base64.urlsafe_b64encode(public_key).decode('utf-8')  
timestamp = int(time.time())  

if payload:  
    dumped = json.dumps(payload, separators=(",", ":"))  
else:  
    dumped = "{}"  

joined_result = normalize_message(payload)  

message = "{}{}".format(  
    base64.urlsafe_b64encode(joined_result.encode()).decode("utf-8"),  
    str(timestamp),  
).encode('utf-8')  

# Create the signature  
signer = PKCS115_SigScheme(private_key)  
signature = signer.sign(SHA256.new(message))  
base64_sign = base64.urlsafe_b64encode(signature).decode('ascii')  

# Prepare the request  
headers = {  
    'content-type': 'application/json',  
    'x-access-token': api_key,  
    'x-access-signature': base64_sign,  
    'x-access-merchant-id': project_id,  
    'x-access-timestamp': str(timestamp),  
}  

if payload:  
    response = requests.post(  
        url,  
        headers=headers,  
        data=dumped,  
    )  
else:  
    response = requests.get(  
        url,  
        headers=headers,  
    )  

# Print the response status  
print(response.status_code)