新的接口验签方式说明

更新于:2019年06月28日 16:23:22

对于 API 文档中要求使用新的验签方式的接口请求,以下是验签的详细说明及注意事项:


 1. 首先必须在 Ping++ 管理平台上[配置商户公钥](https://help.pingxx.com/article/123161)。

 2. RSA-SHA256 签名请使用上述生成的商户私钥,以及请求体 + 请求 URI + 当前时间的 Unix 时间戳生成。

 3. 在请求头中添加以下字段

  • Authorization 字段,其值为 Bearer + API key,例如:Bearer sk_live_*******GujD

  • Pingplusplus-Signature 字段,其值为示例代码中的 $signature

  • Pingplusplus-Request-Timestamp 字段,其值为示例代码中的 $request_time

  • Content-Type 字段,值为 application/json


以下为各个语言签名生成的示例:

PHP :

$request_time = time();//请求时间
$request_body = '<请求内容>';
$request_uri = '/v1/batch_transfers';
$data_to_be_signed = $request_body . $request_uri . $request_time; // 拼接带签名字符串
$private_key = '<商户私钥>';
openssl_sign($data_to_be_signed, $signature, $private_key, 'sha256'); // $private_key 为商户私钥
$signature = base64_encode($signature);// 生成的签名

Node.js:

var requestTime = Date.parse(new Date()) / 1000; // 请求时间
var reuestBody = '<请求内容>';
var privateKey = '<商户私钥>';
var requestUri = '/v1/batch_transfers'; // 请求 URI(包括 URL 参数)
var data = reuestBody + requestUri + requestTime; // 拼接带签名字符串
var sign = crypto.createSign('RSA-SHA256').update(data, "utf8");
var signature = sign.sign(privateKey, 'base64'); // 生成的签名

Ruby:

request_time = Time.now.to_i.to_s # 请求时间
request_body = '<请求内容>'
request_uri = '/v1/batch_transfers' # 请求 URI(包括 URL 参数)
data = request_body + request_uri + request_time; # 拼接带签名字符串
pkey = OpenSSL::PKey.read('<商户私钥>') # 商户私钥
signature = Base64.strict_encode64(pkey.sign(OpenSSL::Digest::SHA256.new, data)) # 生成的签名

Go:

func GenSign(data []byte, privateKey []byte) (sign []byte, err error) {
block, _ := pem.Decode(privateKey)
if block == nil {
return nil, errors.New("private key error")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
hashFunc := crypto.SHA256
h := hashFunc.New()
h.Write(data)
hashed := h.Sum(nil)
return rsa.SignPKCS1v15(rand.Reader, priv, hashFunc, hashed)
}

Python:

# -*- coding: utf-8 -*-
import time
import json
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode
private_key = open('<商户私钥>', "r").read()
request_body = {'<请求内容>'}
if request_body:
    verify_data = [json.dumps(request_body).encode("utf-8")]
else:
    verify_data = []
build_url = '/v1/batch_transfers'  # 请求 URI(包括 URL 参数)
timestamp = int(time.time())
verify_data.extend([build_url, repr(timestamp)])
rsa_data = "".join(verify_data)
rsa_key = RSA.importKey(private_key)
signer = PKCS1_v1_5.new(rsa_key)
digest = SHA256.new(rsa_data)
sign = signer.sign(digest)
signature = b64encode(sign)

C#:

string body = "<请求内容>", sign = "", data = "";
string timestamp = ((DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000).ToString();//请求时间
body = JsonConvert.SerializeObject(param, Formatting.Indented);
string requestUri = "/v1/batch_transfers"; //请求 URI(包括 URL 参数)
data = body + requestUri + timestamp;
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
var privateKeyFile = new FileStream("<商户私钥>", FileMode.Open);
string privateKeyContent = (new StreamReader(privateKeyFile)).ReadToEnd();
privateKeyFile.Close();
privateKeyContent = privateKeyContent.Replace("\r", "").Replace("\n", "");
if (privateKeyContent.StartsWith("-----BEGIN RSA PRIVATE KEY-----"))
{
    privateKeyContent = privateKeyContent.Substring(31);
}
if (privateKeyContent.EndsWith("-----END RSA PRIVATE KEY-----"))
{
    privateKeyContent = privateKeyContent.Substring(0, privateKeyContent.Length - 29);
}
var privateKeyData = Convert.FromBase64String(privateKeyContent);
if (privateKeyData.Length < 162)
{
    throw new PingppException("Private key content is incorrect.");
}
//解析privatekey
var mem = new MemoryStream(privateKeyData);
var binr = new BinaryReader(mem);
try
{
    var twobytes = binr.ReadUInt16();
    switch (twobytes)
    {
        case 0x8130:
            binr.ReadByte();
            break;
        case 0x8230:
            binr.ReadInt16();
            break;
        default:
            return null;
    }
    twobytes = binr.ReadUInt16();
    if (twobytes != 0x0102)
        return null;
    var bt = binr.ReadByte();
    if (bt != 0x00)
        return null;
    var elems = GetIntegerSize(binr);
    var modulus = binr.ReadBytes(elems);
    elems = GetIntegerSize(binr);
    var e = binr.ReadBytes(elems);
    elems = GetIntegerSize(binr);
    var d = binr.ReadBytes(elems);
    elems = GetIntegerSize(binr);
    var p = binr.ReadBytes(elems);
    elems = GetIntegerSize(binr);
    var q = binr.ReadBytes(elems);
    elems = GetIntegerSize(binr);
    var dp = binr.ReadBytes(elems);
    elems = GetIntegerSize(binr);
    var dq = binr.ReadBytes(elems);
    elems = GetIntegerSize(binr);
    var iq = binr.ReadBytes(elems);
    var rsa = new RSACryptoServiceProvider();
    var rsaParam = new RSAParameters
    {
        Modulus = modulus,
        Exponent = e,
        D = d,
        P = p,
        Q = q,
        DP = dp,
        DQ = dq,
        InverseQ = iq
    };
    rsa.ImportParameters(rsaParam);
}
sign = Convert.ToBase64String(rsa.SignData(dataBytes, "SHA256"));

Java:

import org.apache.commons.codec.binary.Base64;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
String requestTime = Integer.valueOf((int) (System.currentTimeMillis() / 1000)).toString(); // 请求时间
String requestBody = "<请求内容>";
String requestUri = "/v1/batch_transfers"; // 请求 URI(包括 URL 参数)
String data = requestBody + requestUri + requestTime; // 拼接待签名字符串
String PEMEncodedPrivateKey = "<商户 PKCS8 私钥>";
PEMEncodedPrivateKey = PEMEncodedPrivateKey.replaceAll("(-+BEGIN (RSA )?PRIVATE KEY-+\\r?\\n|-+END (RSA )?PRIVATE KEY-+\\r?\\n?)", "");
byte[] privateKeyBytes = Base64.decodeBase64(PEMEncodedPrivateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePrivate(keySpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data.getBytes("UTF-8"));
byte[] signBytes = signature.sign();
String signatureString = Base64.encodeBase64String(signBytes).replaceAll("\n|\r", ""); // 生成的签名

    您需要登录后才可以回复