فراخوانیهای تأیید سمت سرور، درخواستهای URL هستند که پارامترهای پرسوجو توسط گوگل گسترش یافتهاند و توسط گوگل به یک سیستم خارجی ارسال میشوند تا به آن اطلاع دهند که کاربر باید به دلیل تعامل با یک تبلیغ بینابینی پاداشدار یا پاداشدار، پاداش دریافت کند. فراخوانیهای SSV پاداشدار (تأیید سمت سرور) یک لایه محافظتی اضافی در برابر جعل فراخوانیهای سمت کلاینت برای پاداش دادن به کاربران فراهم میکنند.
این راهنما به شما نشان میدهد که چگونه با استفاده از کتابخانه رمزنگاری شخص ثالث Tink Java Apps، فراخوانیهای SSV پاداشدار را تأیید کنید تا اطمینان حاصل شود که پارامترهای پرسوجو در فراخوانی، مقادیر معتبری هستند. اگرچه Tink برای اهداف این راهنما استفاده میشود، اما شما میتوانید از هر کتابخانه شخص ثالثی که از ECDSA پشتیبانی میکند، استفاده کنید. همچنین میتوانید سرور خود را با ابزار تست در رابط کاربری AdMob آزمایش کنید.
پیشنیازها
- تأیید سمت سرور پاداشدار را در واحد تبلیغاتی خود فعال کنید.
از کتابخانهی Tink Java Apps از RewardedAdsVerifier استفاده کنید
 مخزن گیتهاب Tink Java Apps شامل یک کلاس کمکی RewardedAdsVerifier است تا کد مورد نیاز برای تأیید یک فراخوانی SSV پاداشدار را کاهش دهد. استفاده از این کلاس به شما امکان میدهد تا یک URL فراخوانی را با کد زیر تأیید کنید.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
    .fetchVerifyingPublicKeysWith(
        RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
    .build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
 اگر متد verify() بدون ایجاد استثنا اجرا شود، URL فراخوانی با موفقیت تأیید شده است. بخش پاداشدهی به کاربر، بهترین شیوهها در مورد زمان پاداشدهی به کاربران را شرح میدهد. برای جزئیات مراحل انجام شده توسط این کلاس برای تأیید فراخوانیهای SSV پاداشدهی شده، میتوانید بخش تأیید دستی SSV پاداشدهی شده را مطالعه کنید.
پارامترهای فراخوانی SSV
فراخوانیهای تأیید سمت سرور شامل پارامترهای پرسوجویی هستند که تعامل تبلیغات پاداشدار را توصیف میکنند. نام پارامترها، توضیحات و مقادیر نمونه در زیر فهرست شدهاند. پارامترها به ترتیب حروف الفبا ارسال میشوند.
| نام پارامتر | توضیحات | مقدار مثال | 
|---|---|---|
| شبکه_تبلیغاتی | شناسه منبع تبلیغاتی برای منبع تبلیغاتی که این تبلیغ را نمایش میدهد. نامهای منبع تبلیغاتی مربوط به مقادیر شناسه در بخش شناسههای منبع تبلیغاتی فهرست شدهاند. | ۱۹۵۳۵۴۷۰۷۳۵۲۸۰۹۰۳۲۵ | 
| واحد_تبلیغاتی | شناسه واحد تبلیغاتی AdMob که برای درخواست تبلیغ جایزهدار استفاده شده است. | ۲۷۴۷۲۳۷۱۳۵ | 
| دادههای سفارشی | رشته داده سفارشی همانطور که توسط customDataارائه شده است.اگر هیچ رشته داده سفارشی توسط برنامه ارائه نشود، مقدار این پارامتر پرس و جو در فراخوانی SSV وجود نخواهد داشت. | نمونه_رشته_داده_سفارشی | 
| کلید_شناسه | کلیدی که برای تأیید فراخوانی SSV استفاده میشود. این مقدار به یک کلید عمومی ارائه شده توسط سرور کلید AdMob نگاشت میشود. | ۱۲۳۴۵۶۷۸۹۰ | 
| مبلغ پاداش | مبلغ پاداش مطابق با تنظیمات واحد تبلیغات. | ۵ | 
| reward_item | مورد پاداش همانطور که در تنظیمات واحد تبلیغ مشخص شده است. | سکهها | 
| امضا | امضای مربوط به فراخوانی SSV که توسط AdMob تولید شده است. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY | 
| مهر زمانی | مهر زمانی که کاربر به عنوان زمان Epoch بر حسب میلیثانیه پاداش دریافت کرده است. | ۱۵۰۷۷۷۰۳۶۵۲۳۷۸۲۳ | 
| شناسه تراکنش | شناسه منحصر به فرد کدگذاری شده با هگز برای هر رویداد اعطای پاداش تولید شده توسط AdMob. | 18fa792de1bca816048293fc71035638 | 
| شناسه_کاربر | شناسه کاربر که توسط userIdارائه شده است.اگر هیچ شناسه کاربری توسط برنامه ارائه نشود، این پارامتر پرس و جو در فراخوانی SSV وجود نخواهد داشت. | ۱۲۳۴۵۶۷ | 
شناسههای منبع تبلیغات
نامها و شناسههای منبع تبلیغات
| نام منبع تبلیغات | شناسه منبع تبلیغ | 
|---|---|
| تولید آگهی (مناقصه) | 1477265452970951479 | 
| ادکولونی | 15586990674969969776 | 
| ادکولونی (مناقصه) | 6895345910719072481 | 
| ادفالکون | 3528208921554210682 | 
| شبکه ادموب | 5450213213286189855 | 
| آبشار شبکه ادموب | 1215381445328257950 | 
| آپلووین | 1063618907739174004 | 
| اپلوین (مناقصه) | 1328079684332308356 | 
| چارتبوست | 2873236629771172317 | 
| پلتفرم شکلات (مناقصه) | 6432849193975106527 | 
| رویداد سفارشی | 18351550913290782395 | 
| صرافی دیتی* * قبل از ۲۱ سپتامبر ۲۰۲۲، این شبکه «بازار فیبر» نام داشت. | 2179455223494392917 | 
| اکواتیو (مناقصه)* * قبل از ۱۲ ژانویه ۲۰۲۳، این شبکه «Smart Adserver» نامیده میشد. | 5970199210771591442 | 
| نوسان (مناقصه) | 8419777862490735710 | 
| تپش | 3376427960656545613 | 
| فیبر* * این منبع آگهی برای گزارشهای تاریخی استفاده میشود. | 4839637394546996422 | 
| آی-موبایل | 5208827440166355534 | 
| بهبود دیجیتال (مناقصه) | 159382223051638006 | 
| بورس شاخص (مناقصه) | 4100650709078789802 | 
| اینموبی | 7681903010231960328 | 
| InMobi (مناقصه) | 6325663098072678541 | 
| صرافی InMobi (پیشنهاد قیمت) | 5264320421916134407 | 
| آیرون سورس | 6925240245545091930 | 
| تبلیغات ironSource (مناقصه) | 1643326773739866623 | 
| لیدبولت | 2899150749497968595 | 
| کسب درآمد از لیفتآف* * قبل از 30 ژانویه 2023، این شبکه «وانگِل» (Vungle) نام داشت. | 1953547073528090325 | 
| کسب درآمد از لیفتآف (مناقصه)* * قبل از 30 ژانویه 2023، این شبکه «Vungle (مناقصه)» نامیده میشد. | 4692500501762622185 | 
| الجی یو+ایدی | 18298738678491729107 | 
| شبکه تبلیغات لاین | 3025503711505004547 | 
| مگنیت دیوی+ (مناقصه) | 3993193775968767067 | 
| مایو | 7505118203095108657 | 
| مایو (مناقصه) | 1343336733822567166 | 
| Media.net (مناقصه) | 2127936450554446159 | 
| تبلیغات خانه با واسطه | 6060308706800320801 | 
| شبکه مخاطبان متا* * پیش از ۶ ژوئن ۲۰۲۲، این شبکه «شبکه مخاطبان فیسبوک» نام داشت. | 10568273599589928883 | 
| شبکه مخاطبان متا (مناقصه)* * پیش از ۶ ژوئن ۲۰۲۲، این شبکه «شبکه مخاطبان فیسبوک (مناقصه)» نامیده میشد. | 11198165126854996598 | 
| انتگرال مینت | 1357746574408896200 | 
| انتگرال منهای (مناقصه) | 6250601289653372374 | 
| موبفاکس (مناقصهدهی) | 3086513548163922365 | 
| MoPub ( منسوخ شده ) | 10872986198578383917 | 
| هدف من | 8450873672465271579 | 
| نند | 9383070032774777750 | 
| نکسن (مناقصه)* * قبل از ۱ مه ۲۰۲۴، این شبکه «UnrulyX» نام داشت. | 2831998725945605450 | 
| صرافی وانتگ (پیشنهاد قیمت) | 4873891452523427499 | 
| OpenX (مناقصه) | 4918705482605678398 | 
| پنگل | 4069896914521993236 | 
| پنگل (مناقصه) | 3525379893916449117 | 
| پابماتیک (مناقصه) | 3841544486172445473 | 
| کمپین رزرو | 7068401028668408324 | 
| سیاره SK | 734341340207269415 | 
| اشتراکگذاری (مناقصه) | 5247944089976324188 | 
| سماتو (مناقصه) | 3362360112145450544 | 
| سونوبی (مناقصه) | 3270984106996027150 | 
| تاپجوی | 7295217276740746030 | 
| تاپجوی (مناقصه) | 4692500501762622178 | 
| تنسنت جیدیتی | 7007906637038700218 | 
| تریپل لیفت (مناقصه) | 8332676245392738510 | 
| تبلیغات یونیتی | 4970775877303683148 | 
| تبلیغات یونیتی (مناقصه) | 7069338991535737586 | 
| گروه ورو (مناقصه دهنده) | 5013176581647059185 | 
| ویپون | 1940957084538325905 | 
| ییلدمو (مناقصه) | 4193081836471107579 | 
| YieldOne (مناقصه) | 3154533971590234104 | 
| زاک | 5506531810221735863 | 
پاداش دادن به کاربر
هنگام تصمیمگیری در مورد زمان پاداش دادن به یک کاربر، ایجاد تعادل بین تجربه کاربری و اعتبارسنجی پاداش بسیار مهم است. فراخوانیهای سمت سرور ممکن است قبل از رسیدن به سیستمهای خارجی با تأخیر مواجه شوند. بنابراین، بهترین روش توصیه شده این است که از فراخوانی سمت کلاینت برای پاداش دادن فوری به کاربر استفاده شود، در حالی که اعتبارسنجی روی همه پاداشها پس از دریافت فراخوانیهای سمت سرور انجام میشود. این رویکرد ضمن تضمین اعتبار پاداشهای اعطا شده، تجربه کاربری خوبی را ارائه میدهد.
با این حال، برای برنامههایی که اعتبار پاداش بسیار مهم است (برای مثال، پاداش بر اقتصاد درون بازی برنامه شما تأثیر میگذارد) و تأخیر در اعطای پاداش قابل قبول است، انتظار برای پاسخ تأیید شده سمت سرور ممکن است بهترین رویکرد باشد.
دادههای سفارشی
 برنامههایی که در فراخوانیهای تأیید سمت سرور به دادههای اضافی نیاز دارند، باید از ویژگی دادههای سفارشی تبلیغات پاداشی استفاده کنند. هر مقدار رشتهای که روی یک شیء تبلیغ پاداشی تنظیم شود، به پارامتر پرسوجوی custom_data از فراخوانی SSV ارسال میشود. اگر هیچ مقدار داده سفارشی تنظیم نشود، مقدار پارامتر پرسوجوی custom_data در فراخوانی SSV وجود نخواهد داشت.
مثال زیر گزینههای SSV را پس از بارگذاری تبلیغ جایزهدار تنظیم میکند:
SAMPLE_CUSTOM_DATA_STRING با دادههای سفارشی خود جایگزین کنید.
اگر میخواهید رشته پاداش سفارشی را تنظیم کنید، باید قبل از نمایش تبلیغ این کار را انجام دهید.
تأیید دستی SSV پاداش داده شده
 مراحل انجام شده توسط کلاس RewardedAdsVerifier برای تأیید SSV پاداش داده شده در زیر شرح داده شده است. اگرچه قطعه کدهای موجود در این کد به زبان جاوا هستند و از کتابخانه شخص ثالث Tink استفاده میکنند، اما این مراحل را میتوانید با زبان دلخواه خود و با استفاده از هر کتابخانه شخص ثالثی که از ECDSA پشتیبانی میکند، پیادهسازی کنید.
دریافت کلیدهای عمومی
برای تأیید یک فراخوانی SSV پاداشدار، به یک کلید عمومی ارائه شده توسط AdMob نیاز دارید.
فهرستی از کلیدهای عمومی که برای اعتبارسنجی فراخوانیهای SSV پاداشدار استفاده میشوند، میتوانند از سرور کلید AdMob دریافت شوند. فهرست کلیدهای عمومی به صورت یک نمایش JSON با فرمتی مشابه زیر ارائه میشود:
{
 "keys": [
    {
      keyId: 1916455855,
      pem: "-----BEGIN PUBLIC KEY-----\nMF...YTPcw==\n-----END PUBLIC KEY-----"
      base64: "MFkwEwYHKoZIzj0CAQYI...ltS4nzc9yjmhgVQOlmSS6unqvN9t8sqajRTPcw=="
    },
    {
      keyId: 3901585526,
      pem: "-----BEGIN PUBLIC KEY-----\nMF...aDUsw==\n-----END PUBLIC KEY-----"
      base64: "MFYwEAYHKoZIzj0CAQYF...4akdWbWDCUrMMGIV27/3/e7UuKSEonjGvaDUsw=="
    },
  ],
}
 برای بازیابی کلیدهای عمومی، به سرور کلید AdMob متصل شوید و کلیدها را دانلود کنید. کد زیر این کار را انجام میدهد و نمایش JSON کلیدها را در متغیر data ذخیره میکند.
String url = ...;
NetHttpTransport httpTransport = new NetHttpTransport.Builder().build();
HttpRequest httpRequest =
    httpTransport.createRequestFactory().buildGetRequest(new GenericUrl(url));
HttpResponse httpResponse = httpRequest.execute();
if (httpResponse.getStatusCode() != HttpStatusCodes.STATUS_CODE_OK) {
  throw new IOException("Unexpected status code = " + httpResponse.getStatusCode());
}
String data;
InputStream contentStream = httpResponse.getContent();
try {
  InputStreamReader reader = new InputStreamReader(contentStream, UTF_8);
  data = readerToString(reader);
} finally {
  contentStream.close();
}
توجه داشته باشید که کلیدهای عمومی مرتباً تغییر میکنند. ایمیلی دریافت خواهید کرد که شما را از تغییر قریبالوقوع مطلع میکند. اگر کلیدهای عمومی را ذخیره میکنید، باید پس از دریافت این ایمیل، کلیدها را بهروزرسانی کنید.
 پس از دریافت کلیدهای عمومی، باید آنها را تجزیه کرد. متد parsePublicKeysJson در زیر، یک رشته JSON، مانند مثال بالا، را به عنوان ورودی دریافت میکند و یک نگاشت از مقادیر key_id به کلیدهای عمومی ایجاد میکند که به صورت اشیاء ECPublicKey از کتابخانه Tink کپسولهسازی شدهاند.
private static Map<Integer, ECPublicKey> parsePublicKeysJson(String publicKeysJson)
    throws GeneralSecurityException {
  Map<Integer, ECPublicKey> publicKeys = new HashMap<>();
  try {
    JSONArray keys = new JSONObject(publicKeysJson).getJSONArray("keys");
    for (int i = 0; i < keys.length(); i++) {
      JSONObject key = keys.getJSONObject(i);
      publicKeys.put(
          key.getInt("keyId"),
          EllipticCurves.getEcPublicKey(Base64.decode(key.getString("base64"))));
    }
  } catch (JSONException e) {
    throw new GeneralSecurityException("failed to extract trusted signing public keys", e);
  }
  if (publicKeys.isEmpty()) {
    throw new GeneralSecurityException("No trusted keys are available.");
  }
  return publicKeys;
}
محتوا را برای تأیید دریافت کنید
 دو پارامتر پرسوجوی آخر در فراخوانیهای SSV پاداشی، همیشه به ترتیب signature و key_id, هستند. پارامترهای پرسوجوی باقیمانده، محتوایی را که باید تأیید شود، مشخص میکنند. فرض کنید AdMob را طوری پیکربندی کردهاید که فراخوانیهای پاداشی را به https://www.myserver.com/mypath ارسال کند. قطعه کد زیر یک نمونه فراخوانی SSV پاداشی را با محتوایی که باید تأیید شود، نشان میدهد.
https://www.myserver.com/path?ad_network=54...55&ad_unit=12345678&reward_amount=10&reward_item=coins ×tamp=150777823&transaction_id=12...DEF&user_id=1234567&signature=ME...Z1c&key_id=1268887
کد زیر نحوه تجزیه محتوایی که قرار است از یک URL فراخوانی شده تأیید شود را به عنوان یک آرایه بایتی UTF-8 نشان میدهد.
public static final String SIGNATURE_PARAM_NAME = "signature=";
...
URI uri;
try {
  uri = new URI(rewardUrl);
} catch (URISyntaxException ex) {
  throw new GeneralSecurityException(ex);
}
String queryString = uri.getQuery();
int i = queryString.indexOf(SIGNATURE_PARAM_NAME);
if (i == -1) {
  throw new GeneralSecurityException("needs a signature query parameter");
}
byte[] queryParamContentData =
    queryString
        .substring(0, i - 1)
        // i - 1 instead of i because of & in the query string
        .getBytes(Charset.forName("UTF-8"));
دریافت امضا و key_id از URL فراخوانی شده
 با استفاده از مقدار queryString از مرحله قبل، پارامترهای query signature و key_id را از URL مربوط به callback، مطابق شکل زیر تجزیه کنید:
public static final String KEY_ID_PARAM_NAME = "key_id=";
...
String sigAndKeyId = queryString.substring(i);
i = sigAndKeyId.indexOf(KEY_ID_PARAM_NAME);
if (i == -1) {
  throw new GeneralSecurityException("needs a key_id query parameter");
}
String sig =
    sigAndKeyId.substring(
        SIGNATURE_PARAM_NAME.length(), i - 1 /* i - 1 instead of i because of & */);
int keyId = Integer.valueOf(sigAndKeyId.substring(i + KEY_ID_PARAM_NAME.length()));
انجام تأیید
 مرحله آخر، تأیید محتوای URL فراخوانی با کلید عمومی مناسب است. نگاشت بازگشتی از متد parsePublicKeysJson را بگیرید و از پارامتر key_id از URL فراخوانی برای دریافت کلید عمومی از آن نگاشت استفاده کنید. سپس امضا را با آن کلید عمومی تأیید کنید. این مراحل در زیر در متد verify نشان داده شده است.
private void verify(final byte[] dataToVerify, int keyId, final byte[] signature)
    throws GeneralSecurityException {
  Map<Integer, ECPublicKey> publicKeys = parsePublicKeysJson();
  if (publicKeys.containsKey(keyId)) {
    foundKeyId = true;
    ECPublicKey publicKey = publicKeys.get(keyId);
    EcdsaVerifyJce verifier = new EcdsaVerifyJce(publicKey, HashType.SHA256, EcdsaEncoding.DER);
    verifier.verify(signature, dataToVerify);
  } else {
    throw new GeneralSecurityException("cannot find verifying key with key ID: " + keyId);
  }
}
اگر متد بدون ایجاد استثنا اجرا شود، URL فراخوانی با موفقیت تأیید شده است.
سوالات متداول
- آیا میتوانم کلید عمومی ارائه شده توسط سرور کلید AdMob را ذخیره کنم؟
- توصیه میکنیم کلید عمومی ارائه شده توسط سرور کلید AdMob را ذخیره کنید تا تعداد عملیات مورد نیاز برای اعتبارسنجی فراخوانیهای SSV کاهش یابد. با این حال، توجه داشته باشید که کلیدهای عمومی مرتباً تغییر میکنند و نباید بیش از 24 ساعت ذخیره شوند.
- کلیدهای عمومی ارائه شده توسط سرور کلید AdMob چند وقت یکبار تغییر میکنند؟
- کلیدهای عمومی ارائه شده توسط سرور کلید AdMob بر اساس یک برنامه متغیر تغییر میکنند. برای اطمینان از اینکه تأیید فراخوانیهای SSV طبق برنامه ادامه مییابد، کلیدهای عمومی نباید بیش از ۲۴ ساعت در حافظه پنهان (cache) نگهداری شوند.
- اگر سرور من قابل دسترسی نباشد چه اتفاقی میافتد؟
-  گوگل برای فراخوانیهای SSV انتظار یک کد پاسخ وضعیت موفقیتآمیز HTTP 200 OKرا دارد. اگر سرور شما قابل دسترسی نباشد یا پاسخ مورد انتظار را ارائه ندهد، گوگل تا پنج بار در فواصل یک ثانیهای دوباره برای ارسال فراخوانیهای SSV تلاش خواهد کرد.
- چگونه میتوانم تأیید کنم که فراخوانیهای SSV از گوگل میآیند؟
- از جستجوی معکوس DNS برای تأیید اینکه فراخوانیهای SSV از گوگل سرچشمه میگیرند، استفاده کنید.