1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/oldsyang-jdpay

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Объяснение

Сделал для WeChat, Alipay и JD Pay. После оплаты через WeChat и Alipay выяснилось, что самая сложная оплата — это JD Pay, и чтобы полностью разработать оплату через JD Pay, нужно внимательно изучить документацию на официальном сайте разработчика JD Pay. Нельзя полагаться на свой опыт, чтобы угадать некоторые процессы, такие как шифрование с открытым и закрытым ключом (без изучения документации вы пожалеете об этом), способ отправки запроса (форма отправляется через HTML-форму, после изучения документации вы поймёте, насколько это странно), переход после успешной оплаты (всё ещё POST, чёрт побери) и отсутствие номера платёжного поручения после успешной оплаты (вам придётся поддерживать его самостоятельно, чёрт побери).

Технические детали

Сначала посетите официальный сайт: http://payapi.jd.com/. Проект использует веб-платформу для оплаты.

  1. Создание единого заказа: https://wepay.jd.com/jdpay/saveOrder.

    • Параметры: http://payapi.jd.com/docList.html?methodName=2.
      • Обязательно внимательно изучите описание этих параметров.
      • Особые параметры:
        • В запросе среди параметров номер продавца — это номер, который система управления продавцами JD Pay присваивает пользователю при регистрации и активации функции оплаты через JD Pay.
        • Номер пользователя — это номер пользователя в системе продавца.
        • Идентификатор транзакции — это уникальный номер, используемый для идентификации каждой транзакции оплаты. Продавец должен гарантировать, что этот идентификатор уникален для каждой транзакции. Повторное использование одного и того же идентификатора может привести к тому, что система будет рассматривать транзакцию как повторную оплату.
        • Правила подписи подробно описаны в разделе «Стандарты безопасности интерфейса — алгоритм подписи».
        • Для обеспечения безопасности все поля в форме, кроме номера продавца (merchant), версии (version) и подписи (sign), должны быть зашифрованы с использованием 3DES.
  2. Генерация подписи

    • Процесс создания подписи состоит из двух этапов: сначала исходные параметры объединяются в одну строку S1 в соответствии с правилами, затем строка S1 используется для создания строки подписи sign с помощью алгоритма подписи.
    • Правила объединения исходных параметров в строку S1:
      • Для запросов с параметрами, отправленными через форму HTML, все параметры сортируются по ASCII-коду имени параметра от меньшего к большему, а затем объединяются с использованием формата ключ-значение URL. Например: k1=value1&k2=value2&k3=value3...
      • Для обмена данными через XML-сообщения каждая строка сообщения объединяется в одну строку без пробелов, которая становится строкой S1. Если сообщение содержит только одну строку, то эта строка становится строкой S1 без дополнительного объединения.
    • Создание подписи:
      • Исходная строка параметров S1 хэшируется с использованием алгоритма SHA256 для получения строки S2.
      • Строка S2 шифруется с помощью закрытого ключа и кодируется в base64 для получения строки подписи sign. Получатель сообщения сначала декодирует строку в base64, затем расшифровывает её с помощью открытого ключа, после чего проверяет подпись на соответствие.
    • Обратите внимание:
      • Пустые параметры не участвуют в создании подписи.
      • Поле sign в списке параметров не участвует в создании подписи.
      • Теги также участвуют в создании подписи для упрощения обработки.
      • Различия между прописными и строчными буквами учитываются.
      • Шифрование RSA выполняется с использованием закрытого ключа отправителя, а расшифровка — с использованием открытого ключа получателя. (Можно использовать инструмент проверки ключей RSA для проверки соответствия открытых и закрытых ключей продавца.)
      • Система проверит действительность открытого ключа продавца.

Пример кода:

def get_sign_str(params, is_compatible=False):
    """
    Генерирует строку подписи
    Args:
        params: словарь данных для подписи
        is_compatible: режим совместимости (подписывает пустые значения в словаре)

    Returns:
        Возвращает подпись
    """

    raw = [(k, params[k]) for k in sorted(params.keys())]
    if is_compatible:
        order_str = "&".join("=".join(kv) for kv in raw)
    else:
        order_str = "&".join("=".join(kv) for kv in raw if kv[1])

    return order_str


def sign(self, prestr):
    """
    Создаёт подпись
    Args:
        prestr(str): исходная строка для подписи

    Returns:
        Возвращает созданную подпись
    """
    key = MRSA.load_key(self.MERCHANT_RSA_PRI_KEY)
    signature = key.private_encrypt(self.sha256(prestr), MRSA.pkcs1_padding)
    sign = base64.b64encode(signature)
    return sign
  1. Шифрование DES3 всех параметров, кроме указанных выше

Чтобы предотвратить раскрытие данных при отправке формы, JD Pay использует DES3 для шифрования всех полей, за исключением указанных выше.

Описание шифрования JD Pay:

  • За исключением особых указаний, данные, передаваемые между продавцом и системой JD Pay, шифруются с использованием 3DES, а затем кодируются в base64.
  • Алгоритм 3DES обозначается как DESede, режим работы — ECB (электронный кодовый блокнот), заполнение не используется (DESede/ECB/NoPadding).
  • Примечание: сервер NoPadding не использует заполнение, поэтому длина исходного текста должна быть кратна 8 (если вы используете предоставленный нами интерфейс API для шифрования, вам не нужно обрабатывать длину исходного текста, интерфейс уже обработал его). Если вы реализуете шифрование самостоятельно, длина исходного текста может не быть кратной 8, в этом случае используйте следующий метод для преобразования в кратную 8 длину:
    1. Преобразуйте исходный текст в массив байтов.
    2. Определите, требуется ли заполнение:
      • Формула: int x = (i + 4) % 8; int y = (x == 0) ? 0 : (8 - x); i — длина массива байтов, y — требуемая длина заполнения.
      • Если y > 0, необходимо добавить заполнение.
    3. Добавьте длину исходного текста в виде 4 байтов в начало массива байтов:
      • Результат[0] = (byte) ((i >> 24) & 0xFF); результат[1] = (byte) ((i >> 16) & 0xFF); результат[2] = (byte) ((i >> 8) & 0xFF); результат[3] = (byte) (i & 0xFF).
    4. Добавьте заполнение в начале массива байтов перед исходным текстом:
      • Пример: строка «1» преобразуется в массив байтов [49], вычисление заполнения y = 3, вычисление длины исходного текста как [0, 0, 0, 1], и окончательный массив байтов становится [0, 0, 0, 1, 49, 0, 0, 0].
  • Способ шифрования формы:
    • При отправке запроса на оплату через форму продавец должен зашифровать все поля, кроме указанных выше, с использованием 3DES.
  • Метод шифрования XML:
    • Данные, отправляемые через интерфейс XML для взаимодействия с сервером JD Pay, должны быть зашифрованы, используя 3DES для всего сообщения, а затем закодированы в base64. Зашифрованные данные должны быть помещены в тег , а поля merchant и version должны быть отдельно помещены в теги .
  • Обработка зашифрованных данных, полученных от JD Pay:
    • После получения зашифрованного ответа от JD Pay сначала проверьте тег на наличие тега и его значение, чтобы убедиться, что ответ нормальный. Затем расшифруйте содержимое тега с помощью base64 и 3DES и получите исходный текст.

Пример кода:

def des_pad(data):
    e = len(data)
    x = (e + 4) % 8
    y = 0 if x == 0 else 8 - x
    sizeByte = struct.pack('>I', e)
    resultByte = range(len(sizeByte) + e + y)
    resultByte[0:4] = sizeByte
    resultByte[4:4 + e] = data
    for i in range(0, y):
        resultByte[e + 4 + i] = "\x00"
    resultstr = ''.join(resultByte)
    return resultstr


def encode_des(to_encode_str, des_key):
    """
    Шифрует данные с помощью DES3
    Args:
        to_encode_str(str): исходный текст, который необходимо зашифровать, здесь текст должен быть дополнен с помощью des_pad
        des_key(str): ключ шифрования
    Returns:

    """

    key = base64.b64decode(des_key)
    des3 = DES3.new(key, DES3.MODE_ECB)
    return des3.encrypt(ToolsClass.des_pad(to_encode_str)).encode('hex_codec')

Таким образом, создание подписи и шифрование завершены, и теперь можно перейти к размещению данных в HTML-форме. Как организовать и реализовать это самостоятельно.

4. Асинхронный обратный вызов

После отправки запроса происходит переход на платёжную страницу JD, где можно оплатить с помощью учётной записи, приложения JD или сканирования QR-кода через WeChat.

Когда пользователь оплачивает с помощью сканирования QR-кода, JD автоматически переходит по указанному вами URL (этот параметр задаётся при отправке платёжного запроса) и асинхронно отправляет POST-запрос на указанный адрес (также задаётся в запросе). Синхронный переход происходит после оплаты со сканированием QR-кода: если страница оплаты JD всё ещё открыта, произойдёт переход. Асинхронная отправка уведомления о результате оплаты происходит всегда. Начинающим важно знать об этом негласном правиле в отрасли (оно также применимо к WeChat, Alipay и другим сервисам). Результаты асинхронного уведомления обязательны для учёта.

Ответ от JD возвращается в формате XML:

<?xml version="1.0" encoding="UTF-8" ?>
<jdpay>
    <version>V2.0</version>
    <merchant>22294531</merchant>
    <result>
        <code>000000</code>
        <desc>success</desc>
    </result>
``` ```
<?xml version="1.0" encoding="UTF-8" >
<jdpay>
  <version>V2.0</version>
  <merchant>110290193003</merchant>
  <result>
    <code>000000</code>
    <desc>success</desc>
  </result>
  <device>6220</device>
  <sign>SJ6qfS+9CmXkt6ghJcf9nIdHJDReTFNkRyjFh5XZAsTAtfHT4SdmKeD88t+2dMnaszJ7vVjBnSu64aJyt6SODW2FHJk0WXEvZNixmo2h8F7vHO5lTE2jEG/9uN7sqg2c7kH2Fnu5cFLCeaMfb8uZqZ8CKi+g7Aw4b6rywvoH/8M=</sign>
  <tradeNum>201704250935156041484635</tradeNum>
  <tradeType>0</tradeType>
  <amount>3140</amount>
  <status>2</status>
  <payList>
    <pay>
      <payType>3</payType>
      <amount>1500</amount>
      <currency>CNY</currency>
      <tradeTime>20170425093516</tradeTime>
     </pay>
     <pay>
       <payType>1</payType>
       <amount>1640</amount>
       <currency>CNY</currency>
       <tradeTime>20170425093516</tradeTime>
       <detail>
         <cardHolderMobile>150****1596</cardHolderMobile>
       </detail>
      </pay>
   </payList>
 </jdpay>

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

На основе демоверсии платёжной системы JD.com. *Примечание: в запросе нет информации о технической направленности текста, поэтому ответ может быть неполным.* Развернуть Свернуть
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/oldsyang-jdpay.git
git@api.gitlife.ru:oschina-mirror/oldsyang-jdpay.git
oschina-mirror
oldsyang-jdpay
oldsyang-jdpay
master