Sdk-h5-server

来自陌陌游戏WIKI
Guo.xiaoyue讨论 | 贡献2021年4月16日 (五) 02:30的版本 游戏内下线通知陌陌

跳转至: 导航搜索

前言

  • 服务端接口调用,构造请求数据并签名必须在商户服务端完成,商户的应用密钥绝对不能保存在商户 APP 客户端中,也不能从服务端下发
  • 请求参数必须是 表单POST提交过来 , Content-Type: application/x-www-form-urlencoded

签名算法

所有接口都需要做参数签名,防止伪造请求

签名算法为:

 1). 参数排序:将所有参数名按字典顺序进行排序[sign字段不参与签名]
 2). 参与签名的数据不要做 URL Encoding,一律以 UTF-8 编码参与签名。
 3). 参数拼接:将所有参数按 k1=v1&k2=v2&k3=v3...格式进行拼接。
 4). 将第3步所得得字符串 &APP_SECRET [每个游戏分配得密钥],生成待签名字符串。
 5). 第4步所得的字符串md5 就是最终的sign了


参考PHP示例:

   <?php
   public function notify() {
   $cp_data_arr = $_POST;  //接收陌陌传递过来的数据详情
   $app_secret = '280ffa37af884aa3abbacb7c01ad16e4’;  //陌陌提供的 app_secret
  
       //根据签名算法拼凑 待签名字符串
       ksort($cp_data_arr);
       $res = ;
       foreach($cp_data_arr as $key=>$value) {
           if($key == 'sign') {
               continue;
           }
           $res .= $key .'='. $value.'&';
       }
       $sign = md5($res.$app_secret);  //待验签字符串

错误码

接口响应ec大于0为错误

错误码 错误描述
21001 接口不存在
21002 appid没有传
21003 userid没传或者是错误的
21004 缺失必传参数
21005 参数错误,值不合法
21006 签名(sign)校验失败
21007 vtoken已过期
21008 vtoken错误
21009 用户未授权登录
21010 消息盒子推送--未配置权限
21011 消息盒子推送失败-用户未开启
21012 道具消耗-道具不存在
21015 道具消耗-服务不可用

接口

登录检验

1). 接口功能

验证用户是否登录。

2). 接口名

https://game.immomo.com/v2/srv/login/check

3). 调用时机

客户端调用SDK登录后,服务器确认此次是否是真实登录

4). 提交参数

参数名 类型 必填 说明
appid string Y 应用ID
sign string Y 参数签名
vtoken string Y 由客户端提交的验证参数
userid string Y 用户ID

注:vtoken对应MMSDK.getUserInfo的vtoken字段,24小时失效,不是token(永久有效)

5). 返回值:(JSON)

 {
   "ec": 0,
   "em": "success",
   "timesec": 1578132537,
   "data": {
       "userid": "UmFXSDh1VVRFcGFpbzNBdG1HNzU5dz09",
       "name": "吴道林",
       "sign": "一天一苹果,疾病远离我",
       "vip": 0,
       "reg_time": 1357445132,
       "constellation": "摩羯座",
       "birthday": "1987-01-15",
       "age": 32,
       "sex": "M",
       "avatar": "https://img.momocdn.com/album/45/AE/45AE5B32-42BB-F81A-409A-777956E45ADA20171204_S.jpg",
       "photo": [
           "45AE5B32-42BB-F81A-409A-777956E45ADA20171204"
       ],
       "city": "隐身",
       "cityid": 110100,
       "big_r": "2"
   }

}

消息盒子推送

接口地址: https://game.immomo.com/v2/srv/message/box

参数:

  1. appid 应用id
  2. userid 用户id, 加密后的momoid
  3. content 发送内容
  4. sign 签名
   返回内容
   {
   "ec": 0,
   "em": "success",
   "timesec": 1578132537,
   "data": {
       "result" => true;
   }

}


数据同步

接口地址: https://game-api.immomo.com/3/server/prop/sync-game-data

参数:

  1. appid 应用id
  2. userid 用户id, 加密后的momoid
  3. type start 游戏开始,score 上报游戏总的分, outcome 游戏胜负结果
  4. time 秒级时间戳
  5. sign 签名
  6. score (int) type = score 时传递
  7. outcome type = outcome 时传递 1.胜利 0.失败
   返回内容
    {
       "ec": 0,
       "em": "success",
       "result": {
           "ec": 200,
           "em": "success",
           "data": [],
       }
   }

游戏室-任务完成上报

陌陌-游戏室-任务中心,约定好的任务完成后触发通知操作

接口地址: https://game.immomo.com/v2/srv/sync/task

参数:

  1. appid 应用id
  2. userid 用户id, 加密后的momoid
  3. task_id 任务id
  4. sign 签名
   返回内容
    {
       "ec": 0,
       "em": "success",
       "result": {
           "ec": 200,
           "em": "success",
           "data": [],
       }
   }

游戏内下线通知陌陌(必须)

游戏内下线通知陌陌,用于中宣部防沉迷行为上报

接口地址: https://game.immomo.com/v2/srv/sync/offline

参数:

  1. appid 应用id
  2. userid 用户id, 加密后的momoid
  3. sign 签名
   返回内容
    {
       "ec": 0,
       "em": "success",
       "result": {
           "ec": 200,
           "em": "success",
           "data": [],
       }
   }

转盘抽奖创建订单

转盘流程时序图: Turntable.png

接口地址: https://game.immomo.com/v2/srv/draw/create

参数:

  1. appid 应用id
  2. userid 用户id, 加密后的momoid
  3. order_id 订单ID (只能包含数字和字母 32位)
  4. type 抽奖类型 1、单抽 10、10抽 100、百抽
  5. awards 抽奖获得的奖品信息 json数组 [{'prop_id' : '111',num:2, begin_consume_time(道具开始消耗时间戳毫秒): 1593500012000}]
  6. extra 扩展参数.json格式
  7. create_time 毫秒时间戳
  1. sign 签名
   返回内容
   {
     "ec": 0,
     "em": "success",
     "timesec": 1578996514,
     "data": {
       "order_id": "202006301523423xxxxxxxxx",
     }
   }

转盘付费道具消耗通知

通过转盘付费抽奖获取的道具,消耗的时候通知

接口地址: https://game.immomo.com/v2/srv/draw/usedNotify

参数:

  1. appid 应用id
  2. userid 用户id, 加密后的momoid
  3. product_id 消耗道具ID
  4. product_num 消耗道具数量
  5. time 毫秒时间戳
  6. sign 签名
   返回内容
   {
      "ec": 0,
      "em": "success",
      "timesec": 1592986638,
      "data": {
         "consumeOrderId": "20200624161718284039623000001"//陌陌道具系统订单ID
      }
   }

支付通知

1).(仔细看这里 ):

   支付成功时陌陌向游戏服务器发起http请求。
   游戏方务必进行RSA签名校验,防止通知内容伪造;   
   同时必须对通知数据中的app_trade_no , total_fee,    product_id,  appid 进行验证, 如果任意一个验证不通过,则表明是异常通知,务必忽略;
   过滤重复的通知
   校验通过之后务必返回给陌陌  success 字符串,否则陌陌认为游戏方没有成功接受支付通知,会重试15次,时间分别是0s,  10s, 25s, 40s ..... 2h17m15s;
   

2). 参数列表

参数名 类型 必选 说明
appid string Y 应用id
momoid string Y 和sdk返回userid一致,即加密后的momoid
trade_no string Y Momo返回的订单号
app_trade_no string Y 游戏商的订单号,(长度不超过64字节
sign string Y 签名
product_id string Y 商品id
currency_type int Y 货币类型 0-人民币
total_fee double Y 价格(单位:元)
trade_time string Y 交易时间戳
is_test_order string Y 是否是测试订单 1-测试订单 0-普通订单
channel_type int Y 支付渠道 3-陌陌币 8-陌陌钱包
encrypted string Y 加密结果[具体加密算法如下]
encrypt_type string Y RSA

以上参数设置以Form格式提交(POST方式给CP通知,需要对参数进行URLDecode处理) CP 返回示例: 成功返回success7个标准字样。 失败返回示例[JSON]:

  {
   ec: 非0错误码,
   em: 错误描述,   //错误描述尽可能简短清晰,便于后期快速查询问题
   }

签名之前,请游戏方先向陌陌索要校验RSA签名所需要的公钥。

签名算法为:

 1). 参数排序:将所有参数名按字母顺序进行排序,没有值的参数不要参与签名。[sign,encrypted,encrypt_type不参与签名]
   注:按照字母顺序进行排序的时候,是按照字符在ASCII码中的顺序进行的从小到大的排序。第一个字符如果一样的话,
    就按照第二个字符在ASCII码中的顺序继续进行排序。如此类推。 
 2). 参与签名的数据不要做 URL Encoding,一律以 UTF-8 编码参与签名。
 3). 参数拼接:将所有参数按 k1=v1&k2=v2&k3=v3...格式进行拼接。
 4). 将第3步所得得字符串 &APP_SECRET [每个游戏分配得密钥],生成待签名字符串。

RSA签名

 当获得到通知返回的待签名字符串后,把待签名字符串,陌陌提供的公钥,陌陌通知返回参数中的参数encrypted的值[base64_decode处理下]
  三者一同放入RSA的签名函数中进行非对称的签名运算,来判断签名是否校验通过。

签名备注: 陌陌在对字符串进行加密的时候使用的是 SHA1withRSA (OPENSSL_ALGO_SHA1)

参考示例:

1、JAVA示例:

 JAVA版本文件:Pay-java-demo.zip

2、PHP示例:

   <?php
   public function notify() {
   $cp_data_arr = $_REQUEST;  //接收陌陌传递过来的数据详情
   $app_secret = '280ffa37af884aa3abbacb7c01ad16e4’;  //陌陌提供的 app_secret
   //陌陌传递数据通过RSA签名方式
   if (isset($cp_data_arr['encrypt_type']) && $cp_data_arr['encrypt_type'] === 'RSA') {
       $appid = $cp_data_arr['appid'];
       //根据签名算法拼凑 待签名字符串
       ksort($cp_data_arr);
       $res = ;
       foreach($cp_data_arr as $key=>$value) {
           if($value ===  || $key == 'encrypted' || $key == 'encrypt_type' || $key == 'sign') {
               continue;
           }
           $res .= $key .'='. $value.'&';
       }
       $data = $res.$app_secret;  //待验签字符串
       $public_key = ;  //陌陌提供的 公钥
       $pu_key = openssl_pkey_get_public($public_key);
       $unsign_msg = base64_decode($cp_data_arr['encrypted']);
       $res = openssl_verify($data, $unsign_msg, $pu_key);
       //error_log("verify result is " . $res);
       if ($res) {
           //执行 发货操作   并 返回陌陌所需要的 success 字样
           echo 'success';
       } else {
           echo 'falied';
       }
   }

}

3、Python示例:

 !/usr/bin/env python
 import base64
  from Crypto.PublicKey import RSA
  from Crypto.Signature import PKCS1_v1_5
  from Crypto.Cipher import PKCS1_OAEP
 from Crypto.Hash import SHA
 if __name__ == '__main__':
   # 应用密钥
   app_secret = 
   # 支付签名检验用的公钥
   pub_key = 
   # http request 参数
   params = {'appid':'appid', 'momoid':'VEgwQng3emRNK2c4Wjd0cW5mcHRUZz09', 'trade_no':'20151026143931553920061', 'app_trade_no':'79396e329eaf4e8b94f27c41cfc7b944-6377453-405-14', 'product_id':'com.wemomo.game.buyu.8', 'currency_type':'0', 'total_fee':'15', 'trade_time':'1445841571', 'channel_type':'5', 'sign':'06c56a89949d617def52f371c357b6db', 'encrypted':'JYoeEzoh6ucdslnYVeqFFBi4NZZRc3vsjjIIH63THISkxGzXkdElCjum7zgWFL9IdacPoESRabG3v9QJARi7vC7byURM3hB9dVFFMFpBWym+LWyW4vgPUQTVfc06JHUAGLKxLMEgq2HKniJPp+5JYw8E+WWB\/TvxuQbOJn6L1sc=', 'encrypt_type':'RSA'}
   # 对http request参数按key排序(升序)并连接起来
   items = params.items()
   items.sort()
   data = 
   for key, value in items:
       if key == 'encrypted' or key == 'encrypt_type' or key == 'sign' or value == :
           continue
       data = data + key + '=' + value + '&'
   data = data + app_secret
   print data
   # 校验签名,其中签名需要base64 decode
   rsa_key = RSA.importKey(pub_key) 
   signature_scheme = PKCS1_v1_5.new(rsa_key) 
   digest = SHA.new(data.encode('utf-8'))
   signature = base64.b64decode(params['encrypted'])
   result = signature_scheme.verify(digest, signature)
   if result:
       print '签名校验通过。'
   else:
       print '签名校验失败。'

4、C++示例

   说明:需要依赖第三方库,地址:http://www.cryptopp.com/

礼包发放通知

1).(仔细看这里 ):

   陌陌-游戏室-礼包中心,用户点击兑换后通知。
   游戏方务必进行RSA签名校验,防止通知内容伪造;   
   根据trade_no做幂等性校验
   

2). 参数列表 post提交, Content-Type: application/x-www-form-urlencoded

参数名 类型 必选 说明
appid string Y 应用id
userid string Y 和sdk返回userid一致,即加密后的momoid
trade_no string Y 用户兑换礼包的订单号
gift_bag_id string Y 游戏商的礼包ID,(长度不超过64字节
trade_time string Y 交易时间戳
sign string Y 签名 等价于支付通知的 `encrypted`, 相同的加密算法


3). 返回值
返回json格式字符串 {"ec":200, "em":"success"};

ec 200表示成功,201 表示用户不存在,202:其他失败情况

4). 加密参考示例

PHP示例:

   <?php
   public function notify() {
   $cp_data_arr = $_POST;  //接收陌陌传递过来的数据详情
   $app_secret = '280ffa37af884aa3abbacb7c01ad16e4’;  //陌陌提供的 app_secret
   $public_key = '’;  //陌陌提供的 RSA 公钥
   
       //拼凑 数据
       ksort($cp_data_arr);
       $res = ;
       foreach($cp_data_arr as $key=>$value) {
           if($key == 'sign') {
               continue;
           }
           $res .= $key .'='. $value.'&';
       }
       $data = md5($res.$app_secret);  //待验签数据
      $pu_key = openssl_pkey_get_public($public_key);
      $unsign_msg = base64_decode($cp_data_arr['sign']);
      $res = openssl_verify($data, $unsign_msg, $pu_key);
      //error_log("verify result is " . $res);
      if ($res) {
          //执行 发货操作   并 返回陌陌所需要的 success 字样
          echo  json_encode(['ec' => 200, 'em' => 'success']);
      } else {
          echo json_encode(['ec' => 202, 'em' => '签名错误']);;
      }
     exit();

转盘抽奖扣费成功通知

1).

   扣费成功时陌陌向游戏服务器发起http请求。
   游戏方务必进行RSA签名校验,防止通知内容伪造;   
   过滤重复的通知。根据order_id做幂等
   校验通过之后务必返回给陌陌  success 字符串,否则陌陌认为游戏方没有成功接受支付通知,会重试15次,时间分别是0s,  10s, 25s, 40s ..... 2h17m15s;

2). 参数列表

参数名 类型 必选 说明
appid string Y 应用id
userid string Y 加密后的momoid
order_id string Y Momo返回的订单号
sign string Y 签名 等价于支付通知的 `encrypted`, 相同的加密算法
is_test string Y 是否是测试订单 1-测试订单 0-普通订单

以上参数设置以Form格式提交(POST方式给CP通知,需要对参数进行URLDecode处理) CP 返回示例: 成功返回success7个标准字样。 失败返回示例[JSON]:

  {
   ec: 非0错误码,
   em: 错误描述,   //错误描述尽可能简短清晰,便于后期快速查询问题
   }