实现服务器到服务器兑换回调
Set up server-to-server callbacks to securely validate rewarded ad completions to help prevent fraud and ensure accurate reward distribution.
阅读时间5 分钟
在奖励玩家时可使用服务器到服务器 (S2S) 回调来检测和防止作弊。
工作原理
当玩家完整观看视频广告时,Unity 广告服务器会向您指定的 URL 发送已签名的回调。这个过程发生在视频实际结束之前,因此可以在玩家返回游戏之前完成奖励循环。
实现
要使用 S2S 回调,您需要在展示广告之前设置服务器 ID (sid)。默认情况下,S2S 兑换回调不可用。如果您需要为项目启用这些回调,请联系支持团队,并在消息中提供您的 Game ID(游戏 ID)及其各自的回调 URL。Unity 将向您发送用于签名和验证回调的密钥哈希值。要在 C# 代码中实现回调,请将 值设置为您的服务器 ID,然后通过 方法传递 options 对象。
ShowOptions.gamerSid
Show
using UnityEngine; using System.Collections; using UnityEngine.Advertisements; public class UnityAdsManager : MonoBehaviour { public string gameId; public string placement = "rewardedVideo" public void ShowAd() { ShowOptions options = new ShowOptions(); // setting the server ID options.gamerSid = "your-side-id"; Advertisement.Show(placementID, options); } }
回调信息
回调来源
回调将来自于此处列出的 IP 地址/网络。该列表将在每个月的第一天更新。发行商可以放心忽略或阻止来自任何其他地方的回调。回调 URL 格式
该请求是对以下格式的 URL 的 HTTP/1.1GET
有关 query 参数的信息,请参阅下表:[CALLBACK_URL][SEPARATOR1]sid=[SID][SEPARATOR]oid=[OID][SEPARATOR]hmac=[SIGNATURE]
参数 | 内容 |
---|---|
| 回调 URL 的基 URL,例如:
|
| 如果 URL 中不存在
|
| 用户 ID 或要发送到终端的任何自定义数据。 |
|
|
| Unity Ads 服务器生成的唯一 Offer ID(优惠 ID)。 |
|
|
| 参数字符串的 HDMAC-MD5 哈希值 例如:
|
https://developer.example.com/award.php?productid=1234&sid=1234567890&oid=0987654321&hmac=106ed4300f91145aff6378a355fced73
回调 URL 的签名
回调 URL 请求会将一个签名附加到 URL 参数。该签名是通过以键值形式连接所有 URL 参数(HMAC 除外,按字母顺序排列并以逗号分隔)创建的参数字符串的 HDMAC-MD5 哈希值。 例如,一个包含 SID 和 OID 的回调 URLhttps://developer.example.com/award.php?productid=1234&sid=1234567890&oid=0987654321
oid=0987654321,productid=1234,sid=1234567890
https://developer.example.com/award.php?productid=1234&sid=1234567890&oid=0987654321&hmac=106ed4300f91145aff6378a355fced73
回调响应
如果该请求通过了所有检查并且用户获得了奖励物品,则 URL 必须以HTTP/1.1 200 OK
1
如果出现错误(例如,OID 已被使用,或签名不匹配,或者当用户未能获得承诺物品时的任何其他错误),服务器应返回HTTP/1.1 200 OK Date: Wed, 22 Feb 2012 23:59:59 GMT Content-Length: 8 1
400
500
HTTP/1.1 400 ERROR Date: Wed, 22 Feb 2012 23:59:59 GMT Content-Length: 12 Duplicate order
node.js 中的回调示例
以下示例演示了如何使用 node.js + express 来验证签名: node.js 中的回调示例// NODE.js S2S callback endpoint sample implementation // Unity Ads var express = require("express") var crypto = require("crypto") var app = express() app.listen(process.env.PORT || 3412) function getHMAC(parameters, secret) { var sortedParameterString = sortParams(parameters) return crypto.createHmac("md5", secret).update(sortedParameterString).digest("hex") } function sortParams(parameters) { var params = parameters || {} return Object.keys(params) .filter((key) => key !== "hmac") .sort() .map((key) => (params[key] === null ? `${key}=` : `${key}=${params[key]}`)) .join(",") } app.get("/", function (req, res) { var sid = req.query.sid var oid = req.query.oid var hmac = req.query.hmac // Save the secret as an environment variable. If none is set, default to xyzKEY var secret = process.env.UNITYADSSECRET || "xyzKEY" var newHmac = getHMAC(req.query, secret) if (hmac === newHmac) { // Signatures match // Check for duplicate oid here (player already received reward) and return 403 if it exists // If there's no duplicate - give virtual goods to player. Return 500 if it fails. // Save the oid for duplicate checking. Return 500 if it fails. // Callback passed, return 200 and include '1' in the message body res.status(200).send("1") } else { // no match res.sendStatus(403) } })
PHP 中的回调示例
以下示例演示了如何在 PHP 中验证签名: PHP 中的回调示例<?php function generate_hash($params, $secret) { ksort($params); // All parameters are always checked in alphabetical order $s = ''; foreach ($params as $key => $value) { $s .= "$key=$value,"; } $s = substr($s, 0, -1); $hash = hash_hmac('md5', $s, $secret); return $hash; } $hash = $_GET['hmac']; unset($_GET['hmac']); $signature = generate_hash($_GET, 'xyzKEY'); // insert here the secret hash key you received from Unity Ads support error_log("req hmac".$hash); error_log("sig hmac".$signature); // check signature if($hash != $signature) { header('HTTP/1.1 403 Forbidden'); echo "Signature did not match"; exit; } // check duplicate orders if(check_duplicate_orders($_GET['oid']) { header('HTTP/1.1 403 Forbidden'); echo "Duplicate order"; exit; } // if not then give the player the item and check that it succeeds. if(!give_item_to_player($_GET['sid'], $_GET['product']) { header('HTTP/1.1 500 Internal Server Error'); echo "Failed to give item to the player"; exit; } // save the order ID for duplicate checking if(save_order_number($_GET['oid']) { header('HTTP/1.1 500 Internal Server Error'); echo "Order ID saving failed, user granted item"; exit; } // everything OK, return "1" header('HTTP/1.1 200 OK'); echo "1"; ?>