1. 开发者服务器接收消息推送

开发者需要按照如下步骤完成:

  1. 填写服务器配置
  2. 验证服务器地址的有效性
  3. 据接口文档实现业务逻辑,接收消息和事件

第一步:填写服务器配置

登录销赞云商家后,在「开发平台」-「消息推送」中,填写服务器地址(URL)、令牌(Token) 和 消息加密密钥(EncodingAESKey)等信息。

  • URL: 开发者用来接收销赞云消息和事件的接口 URL。开发者所填写的URL 必须以 http:// 或 https:// 开头,分别支持 80 端口和 443 端口。
  • Token: 可由开发者可以任意填写,用作生成签名(该 Token 会和接口 URL 中包含的 Token 进行比对,从而验证安全性)。
  • 消息加密密钥: 由开发者手动填写或随机生成,将用作消息体加解密密钥。

同时,开发者可选择消息加解密方式:明文模式(默认)、兼容模式和安全模式。切换加密方式和数据格式需要提前配置好相关代码。 消息配置图片 模式的选择与服务器配置在提交后都会立即生效,请开发者谨慎填写及选择。切换加密方式和数据格式需要提前配置好相关代码,具体见消息加解密

第二步:验证消息的确来自销赞云

提交信息后,销赞云将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:

参数 描述
signature 签名串,signature由填写的token参数和请求中的timestamp参数、nonce参数组合而成。
timestamp 时间戳
nonce 随机数
echostr 随机字符串

开发者通过检验 signature 对请求进行校验(下面有校验方式)。若确认此次 GET 请求来自销赞云,请原样返回echostr参数内容,则接入生效,否则接入失败。 加密/校验流程如下:

  1. 将token、timestamp、nonce三个参数进行字典序排序
  2. 将三个参数字符串拼接成一个字符串进行sha1加密
  3. 开发者获得加密后的字符串可与signature对比,两者一致则表明该请求来源于销赞云,参数没有被篡改

使用本文中Encryptor类的signature方法来生成签名比较,示例PHP代码:

  $sign = Encryptor::signature(Token, $timestamp, $nonce);
  var_dump($sign == $_GET['signature']);

第三步:接收消息和事件

当某些特定的用户操作引发事件推送时(如订单创建、支付、取消等情况),销赞云服务器会将消息(或事件)的数据包以 POST 请求发送到开发者配置的 URL,开发者可以依据自身业务逻辑进行响应。 销赞云服务器在将消息发给开发者服务器地址后,销赞云服务器在五秒内收不到响应会断掉连接。如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。服务器收到请求必须做出下述回复,这样销赞云服务器才不会对此作任何处理,并且不会发起重试,详见下面说明:

  1. 直接回复success(推荐方式)
  2. 直接回复空串(指字节长度为0的空字符串,而不是结构体中content字段的内容为空)

如果开发者希望增强安全性,可以在开发者中心处开启消息加密。

1.1. 消息加解密

开发者在代替授权小程序接收和处理消息时,出于安全考虑,必须对消息收发的过程进行必须的加解密。 具体消息解密的步骤如下:

1.1.1. 验证消息签名

目的是保证消息是来自于销赞云服务器。 根据不同的加密方式,返回的消息格式也有所不同。 销赞云服务会在开发者填写的消息接收URL上会附带上参数nonce、timeStamp、signature、msgSignature(兼容模式和安全模式时返回) 可以使用以上genSignature方法,根据消息验证TOKEN、nonce、timeStamp、encrypt获取签名,和msgSignature比较,如果相同则证明来源于销赞云服务器。 假设用户的clientId、Token、EncodingAESKey分别是:

{
    "clientId": "48ca17b00473d5e595ab",
    "Token": "b303c15a3f6ff8c6d4cde9ba65ccff4d",
    "EncodingAESKey": "EhhkrBZ7zX2rgwRcXIwWSN08ZCGMvwJYN0KzVFgUlUE"
}

销赞云推送消息到URL附带参数为:URL?nonce=57034211&timestamp=1609430400&signature=a4a9fe2142277ef8c06269af6cb261e183a8a597&msgSignature=d04ca45202849b835a6d06ede5644977e022e448

1.明文模式返回消息体:

{
    "clientId": "48ca17b00473d5e595ab",
    "createTime": 1609430400,
    "msgId": 100,
    "msgType": 1,
    "event": "ORDER_CREATE_SUCCESS",
    "content": {
        "id": 1000,
        "orderNo": "1609430400",
        "orderType": 1,
        "orderStatus": 1,
        "orderAmount": 100,
        "closeTime": 1609431000,
        "updateTime": 1609430400
    }
}

2.兼容模式返回消息体:

{
    "clientId": "48ca17b00473d5e595ab",
    "encrypt": "Fy8jMNWDHPqf6Rpj7MQ0s2nXfaCIcnDYrQIx5QOCX0ETw9D5JZE4Q/VwBCsKOARTgXUeMTI0Da4YG2EaqB9m6/6YGEbcqQuECC1ccGmRlNAEDmPaLYoBZcpxvQu6ZJ8J7av7os8xNNGA/QpyOw9xqqOlYOkhZg48+kbCpLjbskw4skFdSIR2jbBUM+iY+lM7EN8SAIQN6Xl0+/m7k0wZgI6ksQdflMLrceAei/zUpK1tLh1wx0TybrNPFFu/9Unn3nXKfQkxfcIMWpgAhUPsGZrgdImEAuH3TCErsHXLOOs3VnGPUupwwUsyOcCP/GI/zROz3hQpPLpX3HlPi9KxLrTZ40znU0RSQ15pOwzHQQjjlVSIOf4DHU2w1gLXKfep",
    "createTime": 1609430400,
    "msgId": 100,
    "msgType": 1,
    "event": "ORDER_CREATE_SUCCESS",
    "content": {
        "id": 1000,
        "orderNo": "1609430400",
        "orderType": 1,
        "orderStatus": 1,
        "orderAmount": 100,
        "closeTime": 1609431000,
        "updateTime": 1609430400
    }
}

3.安全模式返回消息体:

{
    "clientId": "48ca17b00473d5e595ab",
    "encrypt": "Fy8jMNWDHPqf6Rpj7MQ0s2nXfaCIcnDYrQIx5QOCX0ETw9D5JZE4Q/VwBCsKOARTgXUeMTI0Da4YG2EaqB9m6/6YGEbcqQuECC1ccGmRlNAEDmPaLYoBZcpxvQu6ZJ8J7av7os8xNNGA/QpyOw9xqqOlYOkhZg48+kbCpLjbskw4skFdSIR2jbBUM+iY+lM7EN8SAIQN6Xl0+/m7k0wZgI6ksQdflMLrceAei/zUpK1tLh1wx0TybrNPFFu/9Unn3nXKfQkxfcIMWpgAhUPsGZrgdImEAuH3TCErsHXLOOs3VnGPUupwwUsyOcCP/GI/zROz3hQpPLpX3HlPi9KxLrTZ40znU0RSQ15pOwzHQQjjlVSIOf4DHU2w1gLXKfep"
}

1.1.2. 解密消息

encrypt字段为加密消息体,可以使用decrypt方法进行解密,示例PHP代码:

//1.先验证msgSignature,如有
$sign = Encryptor::signature(Token, $timestamp, $nonce, $encrypt);
var_dump($sign == $_GET['msgSignature']);

//2.解密
$aesKey = 'EhhkrBZ7zX2rgwRcXIwWSN08ZCGMvwJYN0KzVFgUlUE';
$res = Encryptor::decrypt($decrypt, EncodingAESKey);
var_dump($res);

注意:

1、AESKey(消息加解密Key)长度固定为43个字符,从a-z,A-Z,0-9共62个字符中选取。 2、出于安全考虑,开放平台网站提供了修改AESKey(消息加解密Key)的功能。

签名和解密类Encryptor,PHP为例:

<?php
/**
 * PHP AES 消息加解密
 */
class Encryptor
{
    public static $blockSize = 32;

    /**
     * SHA1签名.
     * @return string
     */
    public static function signature(): string
    {
        $array = func_get_args();
        sort($array, SORT_STRING);

        return sha1(implode($array));
    }

    /**
     * 对密文进行解密
     * @param string $encrypt
     * @param string $aesKey
     * @return bool|string
     */
    public static function decrypt($encrypt, $aesKey)
    {
        $aseKey = base64_decode($aesKey.'=', true);
        //使用BASE64对需要解密的字符串进行解码
        $cipherText = base64_decode($encrypt);
        $iv = substr($aseKey, 0, 16);
        //解密
        $decrypted = openssl_decrypt($cipherText, 'aes-256-cbc', $aseKey, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
        //去除补位字符
        $result = self::pkcs7Unpad($decrypted);
        //去除16位随机字符串,网络字节序和clientId
        $content = substr($result, 16, strlen($result));
        $contentLen = unpack('N', substr($content, 0, 4))[1];

        return substr($content, 4, $contentLen);
    }

    /**
     * PKCS#7 unpad.
     * @param string $text
     * @return string
     */
    public static function pkcs7Unpad(string $text): string
    {
        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > self::$blockSize) {
            $pad = 0;
        }

        return substr($text, 0, (strlen($text) - $pad));
    }
}

results matching ""

    No results matching ""