签名算法

为保证数据在传输过程中的真实性和完整性,当请求一个API时,你必须对发送的请求加签,并且在获得响应后对响应内容验签。具体的流程请查看消息传输流程图。

准备工作

生成签名需要先创建一对RSA的非对称密钥。非对称密钥包含私钥和公钥,其中私钥用于生成签名,公钥则用于AlphaPay对请求的签名进行验签。

在商户后台进入ECommerce页面,点击编辑公钥,在弹窗中点击点击前往生成打开RSA秘钥生成工具。

在RSA秘钥生成工具中,Key Length选择2048后点击Generate key pair生成。请将生成好的公钥Public key复制回编辑公钥弹窗的输入框中

构建签名

Open API接口需要用SHA256withRSA算法生成签名,转换成Base64编码后再使用URLEncoder进行编码。 签名请求流程:

1. 构建用于签名的内容

签名内容Content_To_Be_Signed的格式为:

<HTTP-Method> <HTTP-URI>
<Merchant-Code>.<Request-Time>.<Nonce>.<Request-Body>

例如:String.format("%s %s\n%s.%s.%s.%s", method, requestURI, merchantCode, requestTime, nonce, body);

其中:

  • HTTP-Method: POST
  • HTTP-URI: 例如完整请求URL是 https://openapi.alphapay.ca/api/v2.0/payments/pay, 那么URI就是 /api/v2.0/payments/pay
  • Merchant-Code: AlphaPay为商户分配的商户编码,例如:CXVJIU
  • Request-Time: 请求时间,格式为ISO 8601,精确到秒,例如:2019-05-28T12:12:12+08:00
  • Nonce: 随机字符串,长度为32位,例如:b111bcf0dfb54d4e8bae68c293d85e2e
  • Request-Body: 请求的body,为JSON 格式,例如:
Request Body
{
    "scenarioCode": "ONLINE_QRCODE",
    "paymentRequestId": "50",
    "order": {
        "orderAmount": {
            "value": "45366",
            "currency": "CNY"
        },
        "description": "This is a test order",
        "notifyUrl": "https://alphapay.com/success",
        "redirectUrl": "https://alphapay.com/successPage"
    },
    "paymentMethod": {
        "paymentMethodType": "Alipay"
    }
}

依照上述规则拼接后的Content_To_Be_Signed则为:

用于签名的内容
POST /api/v2.0/payments/pay
CXVJIU.2019-05-28T12:12:12+08:00.b111bcf0dfb54d4e8bae68c293d85e2e.{
    "scenarioCode": "ONLINE_QRCODE",
    "paymentRequestId": "50",
    "order": {
        "orderAmount": {
            "value": "45366",
            "currency": "CNY"
        },
        "description": "This is a test order",
        "notifyUrl": "https://alphapay.com/success",
        "redirectUrl": "https://alphapay.com/successPage"
    },
    "paymentMethod": {
        "paymentMethodType": "Alipay"
    }
}

2. 生成签名

签名生成的方式如下:

generatedSignature=urlEncode(base64Encode(sha256withrsa(<Content_To_Be_Signed>), <privateKey>)))

其中:

  • sha256withrsa: 通过签名内容生成签名的算法
  • base64Encode: 将签名转为base64编码的算法
  • urlEncode: 为Http请求准备的编码操作
  • Content_To_Be_Signed: 在第一步拼接的签名内容
  • privateKey: 在准备工作部分生成好的私钥

生成完成的签名例子如下:

generated Signature
KrwDE9tAPJYBb4cUZU6ALJxGIZgwDXn5UkFPMip09n%2FkYKPhEIII%2Fki2rYY2lPtuKVgMNz%2BtuCU%2FjzRpohDbrOd8zYriiukpGAxBQDIVbatGI7WYOcc9YVQwdCR6ROuRQvr%2FD1AfdhHd6waAASu5Xugow9w1OW7Ti93LTd0tcyEWQYd2S7c3A73sHOJNYl8DC1PjasiBozZ%2FADgb7ONsqHo%2B8fKHsLygX9cuMkQYTGIRBQsvfgICnJhh%2BzXV8AQoecJBTrv6p%xxxx

3. 在请求头添加签名

基于以下格式组装签名字符串:
'Signature: algorithm=<algorithm>, keyVersion=<keyVersion>, signature=<generatedSignature>'

例如:

Header内Signature完整示例
'Signature: algorithm=RS256, keyVersion=1, signature=d%2FqFC126U57guKgRRXnd4colw5Ed5tpq3NDh2M5JOtfDivAze4X%2BYEaUCWHNW7h02sSed7hsnsDtM2rjtYe8kqAJTV9fMLzraeUZvWBh4j8Sf2D%2Bcz4bJ23S4F7VtoWaxMWjySwWuS0nMQweg%2BM7MY1HQFz2EXZjAa4CVflxU1I61NuEURfiYJGW%2BLEf%2FPVPEgzBLO8LopYMovmgO7Fl97E9UVFZnFW37bSaEdkNCffJlBU00AYWKaXbsARLarETkY9NA8nTJ5yDwjKm4rH3O%2FUhwGYnwLAvozKKjfWLU4m15LoAUF30Tap6d7IGFfewnLxdY34sVYG3Nx6m0Mit%2Bg%3D%3D'

发送请求

构造完成一个包含Merchant-Code, Request-Time, NonceSignature的请求头的请求后,可以使用一些通用工具,如cURL或Postman来发送请求。下面是一个cURL发送请求的例子:

发送请求
curl --location --request POST 'https://openapi.alphapay.ca/api/v2.0/payments/pay' \
--header 'Accept: application/json' \
--header 'Merchant-Code: CXVJIU' \
--header 'Request-Time: 2023-03-15T22:37:47Z' \
--header 'Nonce: b111bcf0dfb54d4e8bae68c293d85e2e' \
--header 'Signature: algorithm=RS256, keyVersion=1, signature=d%2FqFC126U57guKgRRXnd4colw5Ed5tpq3NDh2M5JOtfDivAze4X%2BYEaUCWHNW7h02sSed7hsnsDtM2rjtYe8kqAJTV9fMLzraeUZvWBh4j8Sf2D%2Bcz4bJ23S4F7VtoWaxMWjySwWuS0nMQweg%2BM7MY1HQFz2EXZjAa4CVflxU1I61NuEURfiYJGW%2BLEf%2FPVPEgzBLO8LopYMovmgO7Fl97E9UVFZnFW37bSaEdkNCffJlBU00AYWKaXbsARLarETkY9NA8nTJ5yDwjKm4rH3O%2FUhwGYnwLAvozKKjfWLU4m15LoAUF30Tap6d7IGFfewnLxdY34sVYG3Nx6m0Mit%2Bg%3D%3D' \
--header 'Content-Type: application/json' \
--data-raw '{
    "scenarioCode": "ONLINE_QRCODE",
    "paymentRequestId": "50",
    "order": {
        "orderAmount": {
            "value": "45366",
            "currency": "CNY"
        },
        "description": "This is a test order",
        "notifyUrl": "https://alphapay.com/success",
        "redirectUrl": "https://alphapay.com/successPage"
    },
    "paymentMethod": {
        "paymentMethodType": "Alipay"
    }
}'

处理响应

在接收到AlphaPay的响应后,需要验证响应的签名。首先要组装待验证的内容,然后使用URLDecode来解码签名,再进行Base64解码,最后使用SHA256withRSA算法来验证签名。

验签流程如下:

1. 获取AlphaPay公钥

在商户后台中进入ECommerce中可以查看AlphaPay公钥,如图所示:

2. 构建用于验证的内容

需验证的内容Content_To_Be_Validate的格式为:

<HTTP-Method> <HTTP-URI>
<Merchant-Code>.<Response-Time>.<Nonce>.<Response-Body>
  • HTTP-Method: POST
  • HTTP-URI: 例如完整请求URL是 https://openapi.alphapay.ca/api/v2.0/payments/pay, 那么URI就是 /api/v2.0/payments/pay
  • Merchant-Code: AlphaPay为商户分配的商户编码,例如:CXVJIU
  • Response-Time: 响应时间,格式为ISO 8601,精确到秒,例如:2019-05-28T12:12:12+08:00
  • Nonce: 随机字符串,长度为32位,例如:b111bcf0dfb54d4e8bae68c293d85e2e
  • Response-Body: 响应的body,为JSON 格式

依照上述规则拼接后的Content_To_Be_Validate则为:

用于验证的内容
POST /api/v2.0/payments/pay
CXVJIU.2019-05-28T12:12:12+08:00.b111bcf0dfb54d4e8bae68c293d85e2e.{
 "result": {
    "resultCode":"SUCCESS",
    "resultStatus":"S",
    "resultMessage":"success"
   }
}

3. 从响应头获取签名

目标签名target_signature可以通过响应头的Signature字段获取,详情请查看响应结构部分。

Signature的结构如下:

Signature: algorithm=RSA256, keyVersion=1, signature=<target_signature> 

完整的Signature例子如下:

Signature: algorithm=RS256, keyVersion=1, signature=d%2FqFC126U57guKgRRXnd4colw5Ed5tpq3NDh2M5JOtfDivAze4X%2BYEaUCWHNW7h02sSed7hsnsDtM2rjtYe8kqAJTV9fMLzraeUZvWBh4j8Sf2D%2Bcz4bJ23S4F7VtoWaxMWjySwWuS0nMQweg%2BM7MY1HQFz2EXZjAa4CVflxU1I61NuEURfiYJGW%2BLEf%2FPVPEgzBLO8LopYMovmgO7Fl97E9UVFZnFW37bSaEdkNCffJlBU00AYWKaXbsARLarETkY9NA8nTJ5yDwjKm4rH3O%2FUhwGYnwLAvozKKjfWLU4m15LoAUF30Tap6d7IGFfewnLxdY34sVYG3Nx6m0Mit%2Bg%3D%3D

则所需的签名target_signature为其中signature的值:

d%2FqFC126U57guKgRRXnd4colw5Ed5tpq3NDh2M5JOtfDivAze4X%2BYEaUCWHNW7h02sSed7hsnsDtM2rjtYe8kqAJTV9fMLzraeUZvWBh4j8Sf2D%2Bcz4bJ23S4F7VtoWaxMWjySwWuS0nMQweg%2BM7MY1HQFz2EXZjAa4CVflxU1I61NuEURfiYJGW%2BLEf%2FPVPEgzBLO8LopYMovmgO7Fl97E9UVFZnFW37bSaEdkNCffJlBU00AYWKaXbsARLarETkY9NA8nTJ5yDwjKm4rH3O%2FUhwGYnwLAvozKKjfWLU4m15LoAUF30Tap6d7IGFfewnLxdY34sVYG3Nx6m0Mit%2Bg%3D%3D

4. 验证签名

根据以下方法进行签名的验证:

IS_SIGNATURE_VALID=sha256withrsa_verify(base64Decode(urlDecode(<target_signature>)), <Content_To_Be_Validated>, <serverPublicKey>)
  • sha256withrsa_verify: 验证签名的算法
  • urlDecode: 对接收到的签名进行url解码
  • base64Decode: 签名的base64解码算法
  • target_signature: 从第三步中获取的签名
  • Content_To_Be_Validated: 第二步中构建的待验证的内容
  • serverPublicKey: 在第一步获取的AlphaPay公钥
  • IS_SIGNATURE_VALID: 表示签名是否有效的Boolean
    • true: 签名有效
    • false: 签名无效