التحقق من استدعاءات التحقق من جانب الخادم (SSV)

عمليات استدعاء إثبات الملكية من جانب الخادم هي طلبات عناوين URL، مع مَعلمات طلب البحث بواسطة Google، والتي ترسلها Google إلى نظام خارجي وإشعاره بأنه ينبغي أن يحصل المستخدم على مكافأة مقابل التفاعل مع إعلان إعلان بيني يضم مكافأة طلبات معاودة الاتصال الخاصة بميزة "إثبات الملكية من جهة الخادم" بمكافأة توفير طبقة حماية إضافية ضد انتحال المكالمات من جهة العميل لمكافأة المستخدمين.

يوضح لك هذا الدليل كيفية التحقّق من استدعاءات SSV بمكافأة باستخدام Tink Java Apps التابعة لجهات خارجية للتأكد من أن معاملات الاستعلام في عملية الاستدعاء القيم المشروعة. ورغم استخدام Tink لأغراض هذا الدليل، يمكنك استخدام أي مكتبة تابعة لجهة خارجية ECDSA: يمكنك أيضًا اختبار خادمك باستخدام أداة الاختبار في واجهة مستخدم AdMob.

تحقق من هذا البرنامج الذي يعمل بشكل كامل مثال باستخدام حذاء الربيع لـ Java.

المتطلبات الأساسية

استخدام واجهة BonusedAdsVerifier من مكتبة Tink Java Apps

مستودع Tink Java Apps في GitHub تشتمل على 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

تحتوي استدعاءات التحقق من جهة الخادم على مَعلمات طلب بحث تصف تفاعل مع إعلان يضم مكافأة تكون أسماء المَعلمات والأوصاف وأمثلة القيم الواردة أدناه. يتم إرسال المَعلمات حسب الترتيب الأبجدي.

اسم المعلمة الوصف مثال على القيمة
ad_network معرّف مصدر الإعلان لمصدر الإعلان الذي عرض هذا الإعلان. مصدر الإعلان يتم سرد الأسماء المقابلة لقيم المعرّفات في جدول الإعلانات معرّفات المصادر 1953547073528090325
ad_unit رقم تعريف الوحدة الإعلانية في AdMob التي تم استخدامها لطلب الإعلان الذي يضم مكافأة. 2747237135
key_id المفتاح الذي سيتم استخدامه للتحقُّق من معاودة اتصال ميزة "التحقُّق بخطوتين". يتم ربط هذه القيمة بمفتاح عام. التي يقدّمها خادم مفاتيح مفاتيح AdMob. 1234567890
reward_amount مبلغ المكافأة على النحو المحدّد في إعدادات الوحدة الإعلانية 5
reward_item عنصر المكافأة على النحو المحدّد في إعدادات الوحدة الإعلانية. عملات معدنية
توقيع توقيع معاودة الاتصال الخاصة بميزة "التحقُّق بخطوتين" (SSV) التي أنشأها AdMob MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY
timestamp طابع زمني لوقت مكافأة المستخدم كوقت حقبة بالمللي ثانية 1507770365237823
transaction_id معرّف فريد بترميز سداسي لكل حدث منح مكافأة تنشئه AdMob 18fa792de1bca816048293fc71035638
user_id معرّف المستخدم على النحو المقدَّم من SetUserId

وإذا لم يوفّر التطبيق معرّف المستخدم، لن يتم توفير مَعلمة طلب البحث هذه موجودة في معاودة اتصال SSV.

1234567

معرّفات مصادر الإعلانات

أسماء مصادر الإعلانات وأرقام تعريفها

广告来源名称 广告来源 ID
Aarki(出价)5240798063227064260
Ad Generation(出价)1477265452970951479
AdColony 15586990674969969776
AdColony(非 SDK)(出价)4600416542059544716
AdColony(出价)6895345910719072481
AdFalcon3528208921554210682
AdMob 广告联盟5450213213286189855
AdMob 广告联盟广告瀑布流1215381445328257950
ADResult10593873382626181482
AMoAd17253994435944008978
AppLovin1063618907739174004
AppLovin(出价)1328079684332308356
Chartboost2873236629771172317
Chocolate Platform(出价)6432849193975106527
跨渠道 (MdotM)9372067028804390441
自定义事件18351550913290782395
DT Exchange*
* 在 2022 年 9 月 21 日之前,该广告联盟称为“Fyber Marketplace”。
2179455223494392917
EMX(出价)8497809869790333482
Fluct(出价)8419777862490735710
小风3376427960656545613
Fyber*
* 此广告来源用于生成历史报告。
4839637394546996422
i-mobile5208827440166355534
优化数字化(出价)159382223051638006
Index Exchange(出价)4100650709078789802
InMobi7681903010231960328
InMobi(出价)6325663098072678541
InMobi Exchange(出价)5264320421916134407
IronSource6925240245545091930
ironSource Ads(出价)1643326773739866623
Leadbolt2899150749497968595
LG U+AD18298738678491729107
LINE 广告联盟3025503711505004547
maio7505118203095108657
maio(出价)1343336733822567166
Media.net(出价)2127936450554446159
参与中介的自家广告6060308706800320801
Meta Audience Network*
* 在 2022 年 6 月 6 日之前,该广告联盟称为“Facebook Audience Network”。
10568273599589928883
Meta Audience Network(出价)*
* 在 2022 年 6 月 6 日之前,该广告联盟称为“Facebook Audience Network(出价)”。
11198165126854996598
Mintegral1357746574408896200
Mintegral(出价)6250601289653372374
MobFox8079529624516381459
MobFox(出价)3086513548163922365
MoPub(已弃用10872986198578383917
myTarget8450873672465271579
Nend9383070032774777750
Nexxen(出价)*

* 在 2024 年 5 月 1 日之前,该广告联盟称为“UnrulyX”。

2831998725945605450
ONE by AOL (Millennial Media)6101072188699264581
ONE by AOL (Nexage)3224789793037044399
OneTag Exchange(出价)4873891452523427499
OpenX(出价)4918705482605678398
邦格尔4069896914521993236
Pangle(出价)3525379893916449117
PubMatic(出价)3841544486172445473
预订型广告系列7068401028668408324
RhythmOne(出价)2831998725945605450
Rubicon(出价)3993193775968767067
SK 星球734341340207269415
Sharethrough(出价)5247944089976324188
Smaato(出价)3362360112145450544
Equativ(出价)*

* 在 2023 年 1 月 12 日之前,该广告联盟称为“Smart Adserver”。

5970199210771591442
Sonobi(出价)3270984106996027150
Tapjoy7295217276740746030
Tapjoy(出价)4692500501762622178
Tencent GDT7007906637038700218
TripleLift(出价)8332676245392738510
Unity 广告4970775877303683148
Unity Ads(出价)7069338991535737586
Verizon Media7360851262951344112
Verve Group(出价)5013176581647059185
Vpon1940957084538325905
Liftoff Monetize*

* 在 2023 年 1 月 30 日之前,该广告联盟称为“Vungle”。

1953547073528090325
Liftoff Monetize(出价)*

* 在 2023 年 1 月 30 日之前,该广告联盟称为“Vungle(出价)”。

4692500501762622185
Yieldmo(出价)4193081836471107579
YieldOne(出价)3154533971590234104
Zucks5506531810221735863

مكافأة المستخدم

من المهم تحقيق التوازن بين تجربة المستخدم ومكافأة التحقق من الصحة عند اتخاذ القرار ومتى يتم مكافأة المستخدم. قد تواجه عمليات معاودة الاتصال من جهة الخادم تأخيرات قبل الوصول إلى الأنظمة الخارجية. وبالتالي، فإن أفضل ممارسة موصى بها هي استخدام معاودة الاتصال من جانب العميل لمكافأة المستخدم على الفور، أثناء إجراء التحقق من جميع المكافآت عند استلام استدعاءات من جانب الخادم. هذا النمط تجربة مستخدم جيدة مع ضمان صلاحية والمكافآت.

ومع ذلك، بالنسبة إلى التطبيقات التي تكون فيها صلاحية المكافأة أمرًا بالغ الأهمية (على سبيل المثال، تؤثر المكافآت في اقتصاد تطبيقك داخل اللعبة) ويحدث تأخير في منح المكافآت. مقبول، فقد يكون انتظار معاودة الاتصال التي تم التحقق منها من جانب الخادم هو الأفضل الخاص بك.

البيانات المخصّصة

يجب استخدام التطبيقات التي تتطلب بيانات إضافية في عمليات معاودة الاتصال لإثبات الملكية من جهة الخادم ميزة البيانات المخصّصة للإعلانات التي تضم مكافأة. أي قيمة سلسلة تمّ تحديدها على إعلان يضم مكافأة يتم تمرير الكائن إلى معلَمة طلب البحث custom_data لمعاودة اتصال SSV. إذا كانت الإجابة "لا" البيانات المخصّصة، ولن يتم تغيير قيمة معلَمة طلب البحث custom_data الموجودة في معاودة اتصال SSV.

يوضح نموذج التعليمة البرمجية التالي كيفية تعيين خيارات SSV بعد تم تحميل إعلان يضم مكافأة.

private void LoadRewardedAd(string adUnitId)
{
  // Send the request to load the ad.
  AdRequest adRequest = new AdRequest();
  RewardedAd.Load(adUnitId, adRequest, (RewardedAd rewardedAd, LoadAdError error) =>
  {
    // If the operation failed with a reason.
    if (error != null)
    {
        Debug.LogError("Rewarded ad failed to load an ad with error : " + error);
        return;
    }

    var options = new ServerSideVerificationOptions
                          .Builder()
                          .SetCustomData("SAMPLE_CUSTOM_DATA_STRING")
                          .Build()
    rewardedAd.SetServerSideVerificationOptions(options);
  });
}

إذا كنت تريد ضبط سلسلة المكافأة المخصّصة، عليك إجراء ذلك قبل عرض الإعلان.

إثبات الملكية اليدوي لميزة "التحقّق بخطوتين" (SSV) التي تضم مكافأة

الخطوات التي ينفذها الصف RewardedAdsVerifier للتحقّق من المكافأة تم توضيح ميزة إثبات الملكية من جانب "SSV" أدناه. وعلى الرغم من أن مقتطفات التعليمات البرمجية المضمنة بلغة Java الاستفادة من مكتبة 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
&timestamp=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 من الخطوة السابقة، حلِّل signature key_id مَعلمات طلب البحث من عنوان URL لمعاودة الاتصال كما هو موضّح أدناه:

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 على متغيّر. زمني للمشروع. لضمان استمرار عمل التحقُّق من عمليات معاودة الاتصال باستخدام ميزة "التحقُّق بخطوتين" المقصود، يجب ألّا يتم تخزين المفاتيح العامة مؤقتًا لمدة تزيد عن 24 ساعة.
ماذا يحدث إذا تعذر الوصول إلى خادمي؟
تتوقع Google رمز استجابة لحالة النجاح HTTP 200 OK من أجل إثبات الملكية من جانب الخادم (SSV) مع معاودة الاتصال. إذا تعذر الوصول إلى الخادم أو لم يقدم ستحاول Google إرسال استدعاءات SSV ما يصل إلى خمس مرات في فواصل مدتها ثانية واحدة
كيف يمكنني التحقّق من أنّ طلبات معاودة الاتصال من خلال ميزة إثبات الملكية (SSV) يتم إرسالها من Google؟
يمكنك استخدام بحث نظام أسماء النطاقات العكسي للتحقّق من أنّ عمليات معاودة الاتصال بميزة SSV مصدرها Google.