Sdk-h5-server
目录
前言
- 服务端接口调用,构造请求数据并签名必须在商户服务端完成,商户的应用密钥绝对不能保存在商户 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
参数:
- appid 应用id
- userid 用户id, 加密后的momoid
- content 发送内容
- sign 签名
返回内容 { "ec": 0, "em": "success", "timesec": 1578132537, "data": { "result" => true; }
}
数据同步
接口地址: https://game-api.immomo.com/3/server/prop/sync-game-data
参数:
- appid 应用id
- userid 用户id, 加密后的momoid
- type start 游戏开始,score 上报游戏总的分, outcome 游戏胜负结果
- time 秒级时间戳
- sign 签名
- score (int) type = score 时传递
- outcome type = outcome 时传递 1.胜利 0.失败
返回内容 { "ec": 0, "em": "success", "result": { "ec": 200, "em": "success", "data": [], } }
游戏室-任务完成上报
陌陌-游戏室-任务中心,约定好的任务完成后触发通知操作
接口地址: https://game.immomo.com/v2/srv/sync/task
参数:
- appid 应用id
- userid 用户id, 加密后的momoid
- task_id 任务id
- sign 签名
返回内容 { "ec": 0, "em": "success", "result": { "ec": 200, "em": "success", "data": [], } }
游戏内下线通知陌陌(必须)
游戏内下线通知陌陌,用于中宣部防沉迷行为上报
接口地址: https://game.immomo.com/v2/srv/sync/offline
参数:
- appid 应用id
- userid 用户id, 加密后的momoid
- sign 签名
返回内容 { "ec": 0, "em": "success", "result": { "ec": 200, "em": "success", "data": [], } }
转盘抽奖创建订单
接口地址: https://game.immomo.com/v2/srv/draw/create
参数:
- appid 应用id
- userid 用户id, 加密后的momoid
- order_id 订单ID (只能包含数字和字母 32位)
- type 抽奖类型 1、单抽 10、10抽 100、百抽
- awards 抽奖获得的奖品信息 json数组 [{'prop_id' : '111',num:2, begin_consume_time(道具开始消耗时间戳毫秒): 1593500012000}]
- extra 扩展参数.json格式
- create_time 毫秒时间戳
- sign 签名
返回内容 { "ec": 0, "em": "success", "timesec": 1578996514, "data": { "order_id": "202006301523423xxxxxxxxx", } }
转盘付费道具消耗通知
通过转盘付费抽奖获取的道具,消耗的时候通知
接口地址: https://game.immomo.com/v2/srv/draw/usedNotify
参数:
- appid 应用id
- userid 用户id, 加密后的momoid
- product_id 消耗道具ID
- product_num 消耗道具数量
- time 毫秒时间戳
- 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: 错误描述, //错误描述尽可能简短清晰,便于后期快速查询问题 }