米洛SDK 服务器对接文档
本文档用于游戏服务器端对接米洛SDK平台,包含充值回调接口、签名验证、登录二次验证等完整服务端接入指南。
接口说明
合作商需要开发一个接收充值结果的系统,提供该系统的 URL 给米洛SDK,由米洛SDK发起请求,合作商响应请求。请求协议采用 HTTP POST
1.1.1 通知充值结果
玩家在游戏中使用米洛SDK 进行充值,平台在处理完充值流程之后,主动请求通知游戏方,游戏方返回接收成功(接收成功判断请参考合作商响应请求),平台会启动系统重发机制(一共发送五次,如果五次没有响应将由工作人员补单)。
注意
只有充值成功才会回调通知结果,充值失败的不会通知。
合作商接收到请求后,需要对所有 String 类型的参数值做 urldecode 处理,urldecode 编码统一为 UTF-8,请求参数具体字段说明如下:
| 参数名 | 类型 | 长度 | 参数说明 | 签名顺序 |
|---|---|---|---|---|
orderid |
String |
35 | 平台订单号 | 1 |
cporderid |
String |
35 | 游戏订单号 | 2 |
username |
String |
30 | 平台登录账号 | 3 |
gameid |
int |
11 | 游戏 ID | 4 |
roleid |
String |
30 | 游戏角色 ID | 5 |
serverid |
int |
11 | 服务器 ID | 6 |
amount |
int |
11 | 成功充值金额,单位(元) | 7 |
paytime |
int |
11 | 玩家充值时间,时间戳形式,如 1394087000 | 8 |
extrasparams |
String |
- | 商户拓展参数 | 9 |
sign |
String |
32 | 参数签名(用于验签对比) | 10 |
1.1.2 签名说明
合作商接收到平台的请求后,需要获取相关参数并做验签处理,验签规则如下:以请求参数字段说明中的签名顺序签名,规则为 key=value 的形式,参数之间以"&"符号相连,组成一串字符串。目前包共 10个签名字段。
签名算法为 MD5,统一使用 32 位 UTF-8 加密算法,编码后转为小写与参数中的 sign 进行对比,如果相同-则签名通过,否则-失败。
签名字符串示例
重要说明
下文中的key为服务端的paykey 与登录使用的appkey不同
签名示例
sign = MD5("orderid=100000&cporderid=100000&username=zhangsan&gameid=6&roleid=zhangsanfeng&serverid=1&amount=1&paytime=20130101125612&extrasparams=test&key=123123123213")
注意
- 验签参数值为
urlencode后的内容 - 如果参数没有数据值,请以"key="的形式进行签名,例如:
paytime=&extrasparams=自定义 - 要注意字段的大小写
- key 由米洛SDK提供,登录、充值使用同一个 key
PHP验签示例
PHP
<?php
// 获取参数
$orderid = $_POST['orderid'];
$cporderid = $_POST['cporderid'];
$username = $_POST['username'];
$gameid = $_POST['gameid'];
$roleid = $_POST['roleid'];
$serverid = $_POST['serverid'];
$amount = $_POST['amount'];
$paytime = $_POST['paytime'];
$extrasparams = $_POST['extrasparams'];
$sign = $_POST['sign'];
// 你的paykey
$key = 'YOUR_PAY_KEY';
// 组装签名字符串
$signStr = "orderid={$orderid}&cporderid={$cporderid}&username={$username}&gameid={$gameid}&roleid={$roleid}&serverid={$serverid}&amount={$amount}&paytime={$paytime}&extrasparams={$extrasparams}&key={$key}";
// 计算签名
$mySign = strtolower(md5($signStr));
// 验证签名
if ($mySign === $sign) {
echo 'success';
// 处理充值逻辑
} else {
echo 'errorSign';
}
?>
Java验签示例
Java
import java.security.MessageDigest;
public class SignUtil {
public static boolean verifySign(String orderid, String cporderid, String username,
String gameid, String roleid, String serverid, String amount,
String paytime, String extrasparams, String sign, String key) {
try {
// 组装签名字符串
String signStr = "orderid=" + orderid +
"&cporderid=" + cporderid +
"&username=" + username +
"&gameid=" + gameid +
"&roleid=" + roleid +
"&serverid=" + serverid +
"&amount=" + amount +
"&paytime=" + paytime +
"&extrasparams=" + extrasparams +
"&key=" + key;
// MD5加密
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(signStr.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : array) {
sb.append(String.format("%02x", b));
}
String mySign = sb.toString().toLowerCase();
// 验证签名
return mySign.equals(sign);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
1.1.3 合作商响应请求
合作商接收到平台发出的请求后,以纯字符串的形式返回下列代码:
响应示例
out.print("success");
| 代码 | 代码描述 |
|---|---|
success |
接收成功 |
errorSign |
签名错误 |
error |
未知错误 |
重要
如果合作商未返回"success",平台会启用系统重发机制
1.1.4 温馨提示
建议
-
避免重复发放
由于平台同步系统暂时并不能绝对保证一个订单只同步一次(订单本身是唯一的),因此建议合作商在发放游戏虚拟货币的时候做一次订单的判断,避免同一订单多次发放。 -
处理订单状态变更
总结运营阶段的经验,平台侧发现支付合作商有时候一个订单会同步两次状态,第一次为失败,第二次成功(实际为成功)。因此建议合作商接收同步的订单时处理一下此类情况,例如:系统考虑支持同一个订单,第一次同步失败状态,第二次同步成功状态,系统照常发放游戏币。
1.2 服务器端的登陆二次验证
请求接口
API Endpoint
https://unify.wancms.com/sdkstandard/login/verification
请求参数
| 参数名 | 说明 | 来源 |
|---|---|---|
username |
用户名 | 登录接口返回 |
logintime |
登录时间 | 登录接口返回 |
token |
登录令牌 | 登录接口返回 |
gameid |
游戏ID | 配置的游戏id |
请求方式
- 方法:GET / POST
- 格式:key/value 提交
请求示例
HTTP GET
https://unify.wancms.com/sdkstandard/login/verification?username=wan_xttxtt01&gameid=1&token=448b9c8b521194949e8b6b6ec736781e&logintime=1672797023
返回格式
| 字段 | 说明 |
|---|---|
a |
状态码:成功=1,失败=-1 |
b |
提示信息 |
返回示例
成功响应
JSON
{
"a": 1,
"b": "成功"
}
失败响应
JSON
{
"a": -1,
"b": "验证失败"
}
PHP调用示例
PHP
<?php
$username = 'wan_xttxtt01';
$gameid = 1;
$token = '448b9c8b521194949e8b6b6ec736781e';
$logintime = 1672797023;
$url = "https://unify.wancms.com/sdkstandard/login/verification";
$params = [
'username' => $username,
'gameid' => $gameid,
'token' => $token,
'logintime' => $logintime
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url . '?' . http_build_query($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if ($result['a'] == 1) {
echo "验证成功";
} else {
echo "验证失败:" . $result['b'];
}
?>
Java调用示例
Java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import org.json.JSONObject;
public class LoginVerification {
public static boolean verifyLogin(String username, int gameid,
String token, long logintime) {
try {
String baseUrl = "https://unify.wancms.com/sdkstandard/login/verification";
String params = String.format("?username=%s&gameid=%d&token=%s&logintime=%d",
username, gameid, token, logintime);
URL url = new URL(baseUrl + params);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
JSONObject result = new JSONObject(response.toString());
return result.getInt("a") == 1;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}