文档中心 > 开发指南

奇门发奖对接

更新时间:2025/04/07 访问次数:187

一、能力介绍

发奖方式选择为【奇门回调】时,需要对接该文档中的奇门发奖方式;如发奖方式选择为【小程序内回调】时,无需对接该文档,相关配置请查看广告位创建及设置

奇门的官方集成场景,可以理解为是平台定义好接口的出入参,由三方开发者做具体实现的一种方案。

二、api参数明细查看

针对广告的场景,开发者需要针对每个小游戏,实现“小程序任务奖励发放”场景,点击场景后方的“进入”按钮,可以查看具体的api列表;

核心的api有两个,一个实现奖励发放,一个实现奖励退回,可以分别点击api的“开发文档”,查看对应的出入参说明。

奖励发放接口参数信息展示页如下:

奖励退回接口参数信息展示页如下:

特别注意:当收到奖励退回消息时,若开发者最终决策不进行道具退回等相关操作,也需要在success字段中返回true

三、接口开发

根据上面的文档进行开发,开发后可以自己在本地执行测试,使用业务接收示例并往自己服务地址发送请求。

四、接口验签

为了防止接口被人乱掉用,需要在服务端做验签的逻辑,校验请求的合法性。开发者要求使用验签算法来对请求合法性进行校验。服务端验签可以使用开放sdk提供的工具类SpiUtils,验签失败时候返回“验签失败回应示例”的内容即可,验签逻辑如下。SDK提供有java,c#,php,C,NodeJS版本,如果您不使用SDK,可以根据平台的签名算法,自己实现验签逻辑。

1. 使用开放SDK验签

SDK下载:

/**
* 使用该方法同时请务必要阅读该方法的源码,大致了解该方法的实现。
*
* 如果验签失败则需要返回验签失败的结果,并且需要和配置对应的上,系统才认为是验签成功;
* 
* 如果正确的请求老是误认为验签错误了,则确认以下几点:
* 1编码是否UTF8 
* 2密钥是否写错了,特别是沙箱和线上密钥别搞错
* 3request如果是json,xml类型(form不用理会)则确认inputstream是否被读取过了?如果需要使用body但不想改动麻烦,可以先执行验签,
* 然后在验签结果中获取body(checkResult.getRequestBody()方法)来执行业务逻辑
* 4上层框架是否有做封装导致参数变更
* 如果名以上几点检查没问题,请提供加签前的最终字符串给技术支持协助排查
*/
CheckResult result = SpiUtils.checkSign(request, targetAppSecret);  //这里执行验签逻辑
if(!result.isSuccess()) {  //如果验签失败则需要返回 验签失败的结果,并且需要和配置对应的上,系统才认为是验签成功
  //按验签失败回应示例
}

2. 签名算法

如果开发者想要自己实现验签,可以参考下述签名算法逻辑,完成对应的验签实现。

该场景默认使用的签名算法:MD5(sign_method=md5),签名大体过程如下:

1)对所有API请求参数(包括公共参数和业务参数,但除去sign参数和byte[]类型的参数),根据参数名称的ASCII码表的顺序排序。如:foo:1, bar:2, foo_bar:3, foobar:4排序后的顺序是bar:2, foo:1, foo_bar:3, foobar:4。

2)将排序好的参数名和参数值拼装在一起,根据上面的示例得到的结果为:bar2foo1foo_bar3foobar4。

3)把拼装好的字符串采用utf-8编码,使用签名算法对编码后的字节流进行摘要。如果使用MD5算法,则需要在拼装的字符串前后加上app的secret后,再进行摘要,如:md5(secret+bar2foo1foo_bar3foobar4+secret);如果使用HMAC_MD5算法,则需要用app的secret初始化摘要算法后,再进行摘要,如:hmac_md5(bar2foo1foo_bar3foobar4)。

4)将摘要得到的字节流结果使用十六进制表示,如:hex("helloworld".getBytes("utf-8")) = "68656C6C6F776F726C64"

说明:MD5和HMAC_MD5都是128位长度的摘要算法,用16进制表示,一个十六进制的字符能表示4个位,所以签名后的字符串长度固定为32个十六进制字符。


JAVA签名示例代码

public static String signTopRequest(Map<String, String> params, String secret, String signMethod) throws IOException {
  // 第一步:检查参数是否已经排序
  String[] keys = params.keySet().toArray(new String[0]);
  Arrays.sort(keys);

  // 第二步:把所有参数名和参数值串在一起
  StringBuilder query = new StringBuilder();
  if (Constants.SIGN_METHOD_MD5.equals(signMethod)) { //签名的摘要算法,可选值为:hmac,md5,hmac-sha256
    query.append(secret);
  }
  for (String key : keys) {
    String value = params.get(key);
    if (StringUtils.areNotEmpty(key, value)) {
      query.append(key).append(value);
    }
  }

  // 第三步:使用MD5/HMAC加密
  byte[] bytes;
  if (Constants.SIGN_METHOD_HMAC.equals(signMethod)) {
    bytes = encryptHMAC(query.toString(), secret);
  } else {
    query.append(secret);
    bytes = encryptMD5(query.toString());
  }

  // 第四步:把二进制转化为大写的十六进制(正确签名应该为32大写字符串,此方法需要时使用)
  //return byte2hex(bytes);
}

public static byte[] encryptHMAC(String data, String secret) throws IOException {
  byte[] bytes = null;
  try {
    SecretKey secretKey = new SecretKeySpec(secret.getBytes(Constants.CHARSET_UTF8), "HmacMD5");
    Mac mac = Mac.getInstance(secretKey.getAlgorithm());
    mac.init(secretKey);
    bytes = mac.doFinal(data.getBytes(Constants.CHARSET_UTF8));
  } catch (GeneralSecurityException gse) {
    throw new IOException(gse.toString());
  }
  return bytes;
}

public static byte[] encryptMD5(String data) throws IOException {
  return encryptMD5(data.getBytes(Constants.CHARSET_UTF8));
}
public static byte[] encryptMD5(byte[] data) throws IOException {
  byte[] bytes = null;
  try {
    MessageDigest md = MessageDigest.getInstance("MD5");
    bytes = md.digest(data);
  } catch (GeneralSecurityException gse) {
    throw new IOException(gse.toString());
  }
  return bytes;
}
public static String byte2hex(byte[] bytes) {
  StringBuilder sign = new StringBuilder();
  for (int i = 0; i < bytes.length; i++) { 
    String hex = Integer.toHexString(bytes[i] & 0xFF);
    if (hex.length() == 1) { 
      sign.append("0"); 
    }
    sign.append(hex.toUpperCase()); 
  }
  return sign.toString(); 
}


C#签名示例代码

public static string SignTopRequest(IDictionary<string, string> parameters, string secret, string signMethod)
{
  // 第一步:把字典按Key的字母顺序排序
  IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters, StringComparer.Ordinal);
  IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();

  // 第二步:把所有参数名和参数值串在一起
  StringBuilder query = new StringBuilder();
  if (Constants.SIGN_METHOD_MD5.Equals(signMethod)) //签名的摘要算法,可选值为:hmac,md5,hmac-sha256
  {
    query.Append(secret);
  }
  while (dem.MoveNext())
    {
      string key = dem.Current.Key;
      string value = dem.Current.Value;
      if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
      {
        query.Append(key).Append(value);
      }
    }

  // 第三步:使用MD5/HMAC加密
  byte[] bytes;
  if (Constants.SIGN_METHOD_HMAC.Equals(signMethod))
  {
    HMACMD5 hmac = new HMACMD5(Encoding.UTF8.GetBytes(secret));
    bytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(query.ToString()));
  }
  else
  {
    query.Append(secret);
    MD5 md5 = MD5.Create();
    bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(query.ToString()));
  }

  // 第四步:把二进制转化为大写的十六进制
  StringBuilder result = new StringBuilder();
  for (int i = 0; i < bytes.Length; i++)
  {
    result.Append(bytes[i].ToString("X2"));
  }

  return result.ToString();
}

下一篇:广告位开关打开和关闭

FAQ

关于此文档暂时还没有FAQ
返回
顶部