קריאות חוזרות (callback) לאימות בצד השרת הן בקשות לכתובות URL, עם פרמטרים של שאילתות מורחבים על ידי Google, שנשלחים על ידי Google למערכת חיצונית כדי ליידע את המשתמש שצריך לקבל תגמול על אינטראקציה עם מודעה מתגמלת או מודעת מעברון מתגמלת. קריאה חוזרת (callback) של SSV מתגמל (אימות בצד השרת) מספקים שכבה נוספת של הגנה מפני זיוף של קריאות חוזרות (callback) בצד הלקוח כדי לתגמל משתמשים.
במדריך הזה מוסבר איך לאמת התקשרות חזרה של SSV מתגמל. Tink Java Apps של צד שלישי ספרייה קריפטוגרפית כדי לוודא שהפרמטרים של השאילתה בקריאה החוזרת והערכים הלגיטימיים. על אף ש-Tink משמש למדריך זה, יש לך אפשרות משתמשים בכל ספרייה של צד שלישי שתומכת ECDSA. אפשר גם לבדוק את השרת באמצעות הבדיקה בממשק המשתמש של AdMob.
רוצה לראות איך זה עובד? דוגמה באמצעות Spring-boot.
דרישות מוקדמות
שילוב מודעות מתגמלות אפליקציה לנייד עם גרסה 11.6.0 ואילך של Google Mobile Ads SDK.
הפעלה של בצד השרת המתגמלות אימות ביחידת המודעות.
שימוש ב-RewardedAdsVerifier מספריית האפליקציות של Tink ל-Java
מאגר Tink Java Apps ב-GitHub
כוללת
RewardedAdsVerifier
Assistant מסוג 'עוזר דיגיטלי' כדי להקטין את הקוד שנדרש לאימות קריאה חוזרת של SSV מתגמל.
שימוש בכיתה הזו מאפשר לכם לאמת כתובת URL לקריאה חוזרת (callback) באמצעות הקוד הבא.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
אם ה-method verify()
פועלת בלי להעלות חריג, הקריאה החוזרת (callback)
כתובת ה-URL אומתה בהצלחה. האפשרות תגמול המשתמש
בקטע 'שיטות מומלצות' לגבי המקרים שבהם המשתמשים צריכים לקבל תגמול. עבור
פירוט השלבים שבוצעו על ידי הכיתה הזו כדי לאמת התקשרות חזרה של SSV מתגמל,
ניתן לקרוא את האימות הידני של מודעות מתגמלות
SSV.
פרמטרים של קריאה חוזרת ל-SSV
קריאות חוזרות לאימות בצד השרת מכילות פרמטרים של שאילתה שמתארים את אינטראקציה עם מודעות מתגמלות. שמות הפרמטרים, התיאורים והערכים לדוגמה הם שמפורטות בהמשך. הפרמטרים נשלחים בסדר אלפביתי.
שם פרמטר | תיאור | ערך לדוגמה |
---|---|---|
ad_network | המזהה של מקור המודעות שהגיש את המודעה. מקור המודעה שמות התואמים לערכי המזהה מופיעים בעמודה מודעה מזהי מקורות. | 1953547073528090325 |
ad_unit | מזהה יחידת המודעות ב-AdMob שדרכו נשלחה הבקשה להצגת המודעה המתגמלת. | 2747237135 |
custom_data | מחרוזת נתונים מותאמת אישית כפי שסופקה על ידי
setCustomData
.
אם האפליקציה לא מספקת מחרוזת נתונים מותאמת אישית, פרמטר השאילתה הזה לא יופיע בקריאה החוזרת של ה-SSV. |
SAMPLE_CUSTOM_DATA_STRING |
key_id | מפתח שמשמש לאימות קריאה חוזרת של SSV. הערך הזה ממופה למפתח ציבורי שסופק על ידי שרת המפתחות של AdMob. | 1234567890 |
reward_amount | סכום התגמול כפי שצוין בהגדרות של יחידת המודעות. | 5 |
reward_item | פריט התגמול כפי שצוין בהגדרות של יחידת המודעות. | מטבעות |
signature | חתימה לקריאה חוזרת של SSV שנוצרה על ידי AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
חותמת זמן | חותמת הזמן של מועד התגמול של המשתמש כזמן של תקופה של זמן מערכת באלפיות השנייה. | 1507770365237823 |
transaction_id | מזהה ייחודי בקידוד הקסדצימלי לכל אירוע של הענקת פרס שנוצר על ידי AdMob. | 18fa792de1bca816048293fc71035638 |
user_id | מזהה המשתמש כפי שסופק על ידי
setUserId .
אם האפליקציה לא מספקת מזהה משתמש, פרמטר השאילתה הזה לא יהיה בקריאה החוזרת של ה-SSV. |
1234567 |
מזהים של מקורות מודעות
שמות ומזהים של מקורות מודעות
广告来源名称 | 广告来源 ID |
---|---|
Aarki(出价) | 5240798063227064260 |
Ad Generation(出价) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony(非 SDK)(出价) | 4600416542059544716 |
AdColony(出价) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
AdMob 广告联盟 | 5450213213286189855 |
ADResult | 10593873382626181482 |
AMoAd | 17253994435944008978 |
AppLovin | 1063618907739174004 |
AppLovin(出价) | 1328079684332308356 |
查特波斯特 | 2873236629771172317 |
Chocolate Platform(出价) | 6432849193975106527 |
跨渠道 (MdotM) | 9372067028804390441 |
自定义事件 | 18351550913290782395 |
DT Exchange* * 在 2022 年 9 月 21 日之前,该广告联盟称为“Fyber Marketplace”。 | 2179455223494392917 |
EMX(出价) | 8497809869790333482 |
Fluct(出价) | 8419777862490735710 |
小风 | 3376427960656545613 |
Fyber* * 此广告来源用于生成历史报告。 | 4839637394546996422 |
i-mobile | 5208827440166355534 |
优化数字化(出价) | 159382223051638006 |
Index Exchange(出价) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi(出价) | 6325663098072678541 |
IronSource | 6925240245545091930 |
ironSource Ads(出价) | 1643326773739866623 |
Leadbolt | 2899150749497968595 |
LG U+AD | 18298738678491729107 |
LINE 广告联盟 | 3025503711505004547 |
maio | 7505118203095108657 |
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 |
Mintegral | 1357746574408896200 |
Mintegral(出价) | 6250601289653372374 |
MobFox | 8079529624516381459 |
MobFox(出价) | 3086513548163922365 |
MoPub(已弃用) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
Nexxen(出价)* * 在 2024 年 5 月 1 日之前,该广告联盟称为“UnrulyX”。 | 2831998725945605450 |
ONE by AOL (Millennial Media) | 6101072188699264581 |
ONE by AOL (Nexage) | 3224789793037044399 |
OneTag Exchange(出价) | 4873891452523427499 |
OpenX(出价) | 4918705482605678398 |
Pangle(出价) | 3525379893916449117 |
PubMatic(出价) | 3841544486172445473 |
预订型广告系列 | 7068401028668408324 |
RhythmOne(出价) | 2831998725945605450 |
Rubicon(出价) | 3993193775968767067 |
SK 星球 | 734341340207269415 |
Sharethrough(出价) | 5247944089976324188 |
Smaato(出价) | 3362360112145450544 |
Equativ(出价)* * 在 2023 年 1 月 12 日之前,该广告联盟称为“Smart Adserver”。 | 5970199210771591442 |
Sonobi(出价) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy(出价) | 4692500501762622178 |
Tencent GDT | 7007906637038700218 |
TripleLift(出价) | 8332676245392738510 |
Unity 广告 | 4970775877303683148 |
Unity Ads(出价) | 7069338991535737586 |
Verizon Media | 7360851262951344112 |
Verve Group(出价) | 5013176581647059185 |
弗蓬 | 1940957084538325905 |
Liftoff Monetize* * 在 2023 年 1 月 30 日之前,该广告联盟称为“Vungle”。 | 1953547073528090325 |
Liftoff Monetize(出价)* * 在 2023 年 1 月 30 日之前,该广告联盟称为“Vungle(出价)”。 | 4692500501762622185 |
Yieldmo(出价) | 4193081836471107579 |
YieldOne(出价) | 3154533971590234104 |
Zucks | 5506531810221735863 |
תגמול למשתמשים
כשמקבלים החלטה, חשוב לאזן בין חוויית המשתמש לבין אימות התגמול מתי לתגמל משתמש. ייתכנו עיכובים בקריאות חוזרות בצד השרת להגיע למערכות חיצוניות. לכן, השיטה המומלצת היא להשתמש הקריאה החוזרת בצד הלקוח כדי לתגמל את המשתמש באופן מיידי, תוך כדי ביצוע אימות של כל התגמולים עם קבלת הקריאות החוזרות בצד השרת. הזה מספקת חוויית משתמש טובה תוך הבטחת תקפות בפרסים.
עם זאת, באפליקציות שבהן תוקף התגמולים הוא קריטי (לדוגמה, הפרס משפיע על כלכלת האפליקציה במשחק) והעיכובים בהענקת פרסים הם סביר, המתנה לקריאה חוזרת (callback) מאומתת בצד השרת .
נתונים בהתאמה אישית
אפליקציות שדורשות נתונים נוספים בקריאות חוזרות (callback) של אימות בצד השרת
פיצ'ר הנתונים בהתאמה אישית במודעות המתגמלות. כל ערך מחרוזת שמוגדר במודעה מתגמלת
האובייקט מועבר אל פרמטר השאילתה custom_data
של הקריאה החוזרת ל-SSV. אם לא
מוגדר ערך של נתונים מותאמים אישית, ערך הפרמטר custom_data
של השאילתה לא יהיה
נמצאים בקריאה החוזרת של ה-SSV.
דוגמת הקוד הבאה מדגימה איך להגדיר את אפשרויות ה-SSV אחרי המודעה המתגמלת נטענה.
Java
RewardedAd.load(MainActivity.this, "ca-app-pub-3940256099942544/5354046379", new AdRequest.Builder().build(), new RewardedAdLoadCallback() { @Override public void onAdLoaded(RewardedAd ad) { Log.d(TAG, "Ad was loaded."); rewardedAd = ad; ServerSideVerificationOptions options = new ServerSideVerificationOptions .Builder() .setCustomData("SAMPLE_CUSTOM_DATA_STRING") .build(); rewardedAd.setServerSideVerificationOptions(options); } @Override public void onAdFailedToLoad(LoadAdError loadAdError) { Log.d(TAG, loadAdError.toString()); rewardedAd = null; } });
Kotlin
RewardedAd.load(this, "ca-app-pub-3940256099942544/5354046379", AdRequest.Builder().build(), object : RewardedAdLoadCallback() { override fun onAdLoaded(ad: RewardedAd) { Log.d(TAG, "Ad was loaded.") rewardedInterstitialAd = ad val options = ServerSideVerificationOptions.Builder() .setCustomData("SAMPLE_CUSTOM_DATA_STRING") .build() rewardedAd.setServerSideVerificationOptions(options) } override fun onAdFailedToLoad(adError: LoadAdError) { Log.d(TAG, adError?.toString()) rewardedAd = null } })
כדי להגדיר את מחרוזת התגמולים המותאמת אישית, עליך לעשות זאת לפני ההצגה את המודעה.
אימות ידני של אימות דו-שלבי (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();
}
חשוב לזכור שמפתחות ציבוריים עוברים רוטציה באופן קבוע. יישלח אליך אימייל כדי להודיע על כך לגבי סבב קרוב. אם המפתחות הציבוריים נשמרים במטמון, צריך לעדכן אותם המפתחות.
אחרי אחזור המפתחות הציבוריים, יש לנתח אותם.
ה-method 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 לשליחת קריאה חוזרת (callback) של תגמולים אל
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 לקריאה חוזרת (callback) כמערך בייטים מסוג 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 לקריאה חוזרת (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);
}
}
אם ה-method פועלת מבלי להקפיץ הודעת שגיאה, כתובת ה-URL של הקריאה החוזרת (callback) הייתה אומת בהצלחה.
שאלות נפוצות
- האם אפשר לשמור במטמון את המפתח הציבורי שסופק על ידי שרת המפתחות של AdMob?
- מומלץ לשמור במטמון את המפתח הציבורי שסופק על ידי מפתח AdMob שרת לצמצום מספר הפעולות הנדרשות לאימות SSV קריאה חוזרת (callback). עם זאת, חשוב לדעת שמפתחות ציבוריים עוברים רוטציה באופן קבוע, יישמרו במטמון למשך יותר מ-24 שעות.
- באיזו תדירות מתבצעת רוטציה של המפתחות הציבוריים שמסופקים על ידי שרת המפתחות של AdMob?
- המפתחות הציבוריים שמסופקים על ידי שרת המפתחות של AdMob מוחלפים במשתנה לוח זמנים. כדי להבטיח שהאימות של קריאה חוזרת (callback) של SSV ימשיך לפעול כמו אין לשמור במטמון מפתחות ציבוריים למשך יותר מ-24 שעות.
- מה קורה אם לא ניתן להגיע לשרת שלי?
- Google מצפה לקוד תגובה של
HTTP 200 OK
לסטטוס הצלחה עבור SSV קריאה חוזרת (callback). אם לא ניתן להגיע לשרת או שהוא לא מספק את הצפי תגובה, Google תנסה לשלוח שוב התקשרות חזרה של SSV עד חמש פעמים במרווחי זמן של שנייה אחת. - איך אפשר לוודא שהקריאות החוזרות של בצד שלישי מגיעות מ-Google?
- להשתמש בשאילתת DNS הפוכה כדי לאמת שהקריאות החוזרות של SSV מגיעות מ-Google.