Wywołania zwrotne w ramach weryfikacji po stronie serwera to żądania URL z parametrami zapytania rozszerzonymi przez Google, które są wysyłane przez Google do systemu zewnętrznego, aby powiadomić go, że użytkownik powinien otrzymać nagrodę za interakcję z reklamą z nagrodą lub pełnoekranową reklamą z nagrodą. Wywołania zwrotne SSV (weryfikacja po stronie serwera) w przypadku reklam z nagrodą zapewniają dodatkową ochronę przed fałszowaniem wywołań zwrotnych po stronie klienta w celu przyznawania użytkownikom nagród.
Z tego przewodnika dowiesz się, jak weryfikować wywołania zwrotne SSV dotyczące reklam z nagrodą za pomocą biblioteki kryptograficznej innej firmy Tink Java Apps, aby mieć pewność, że parametry zapytania w wywołaniu zwrotnym mają prawidłowe wartości. W tym przewodniku używamy biblioteki Tink, ale możesz użyć dowolnej biblioteki innej firmy, która obsługuje algorytm ECDSA. Serwer możesz też przetestować za pomocą narzędzia do testowania w interfejsie AdMob.
Zapoznaj się z przykładem SSV z nagrodą przy użyciu Java Spring Boot.
Wymagania wstępne
- Włącz weryfikację po stronie serwera w przypadku reklam z nagrodą w jednostce reklamowej.
Używanie klasy RewardedAdsVerifier z biblioteki Tink Java Apps
Repozytorium GitHub Tink Java Apps zawiera RewardedAdsVerifier
klasę pomocniczą, która zmniejsza ilość kodu potrzebnego do weryfikacji wywołania zwrotnego SSV za nagrodę.
Użycie tej klasy umożliwia weryfikację adresu URL wywołania zwrotnego za pomocą poniższego kodu.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
Jeśli metoda verify()
zostanie wykonana bez zgłaszania wyjątku, adres URL wywołania zwrotnego zostanie zweryfikowany. W sekcji Nagradzanie użytkownika znajdziesz szczegółowe informacje o sprawdzonych metodach dotyczących tego, kiedy należy nagradzać użytkowników. Szczegółowe informacje o krokach wykonywanych przez tę klasę w celu weryfikacji wywołań zwrotnych SSV w przypadku reklam z nagrodą znajdziesz w sekcji Ręczna weryfikacja SSV w przypadku reklam z nagrodą.
Parametry wywołania zwrotnego SSV
Wywołania zwrotne w ramach weryfikacji po stronie serwera zawierają parametry zapytania opisujące interakcję z reklamą z nagrodą. Poniżej znajdziesz nazwy parametrów, ich opisy i przykładowe wartości. Parametry są wysyłane w kolejności alfabetycznej.
Nazwa parametru | Opis | Przykładowa wartość |
---|---|---|
ad_network | Identyfikator źródła reklam, które wyświetliło tę reklamę. Nazwy źródeł reklam odpowiadające wartościom identyfikatorów są podane w sekcji Identyfikatory źródeł reklam. | 1953547073528090325 |
ad_unit | Identyfikator jednostki reklamowej AdMob, który został użyty do wysłania żądania reklamy z nagrodą. | 2747237135 |
custom_data | Niestandardowy ciąg danych podany przez
setCustomData .
Jeśli aplikacja nie poda niestandardowego ciągu danych, ten parametr zapytania nie będzie obecny w wywołaniu zwrotnym SSV. |
SAMPLE_CUSTOM_DATA_STRING |
key_id | Klucz używany do weryfikacji wywołania zwrotnego SSV. Ta wartość jest powiązana z kluczem publicznym udostępnianym przez serwer kluczy AdMob. | 1234567890 |
reward_amount | Wysokość nagrody określona w ustawieniach jednostki reklamowej. | 5 |
reward_item | Przedmiot nagrody określony w ustawieniach jednostki reklamowej. | monety |
podpis | Podpis wywołania zwrotnego SSV wygenerowany przez AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
sygnatura czasowa | Sygnatura czasowa momentu przyznania użytkownikowi nagrody w milisekundach od początku epoki. | 1507770365237823 |
transaction_id | Niepowtarzalny identyfikator zakodowany w systemie szesnastkowym dla każdego zdarzenia przyznania nagrody wygenerowanego przez AdMob. | 18fa792de1bca816048293fc71035638 |
user_id | Identyfikator użytkownika podany przez setUserId .
Jeśli aplikacja nie podaje identyfikatora użytkownika, ten parametr zapytania nie będzie obecny w wywołaniu zwrotnym SSV. |
1234567 |
Identyfikatory źródła reklam
Nazwy i identyfikatory źródeł reklam
Nazwa źródła reklamy | Identyfikator źródła reklamy |
---|---|
Ad Generation (określanie stawek) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony (określanie stawek) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
Sieć AdMob | 5450213213286189855 |
Kaskada sieci AdMob | 1215381445328257950 |
AppLovin | 1063618907739174004 |
AppLovin (określanie stawek) | 1328079684332308356 |
Chartboost | 2873236629771172317 |
Chocolate Platform (określanie stawek) | 6432849193975106527 |
Zdarzenie niestandardowe | 18351550913290782395 |
DT Exchange* * Przed 21 września 2022 r. ta sieć nazywała się „Fyber Marketplace”. | 2179455223494392917 |
Equativ (określanie stawek)* * Przed 12 stycznia 2023 r. ta sieć nosiła nazwę „Smart Adserver”. | 5970199210771591442 |
Fluct (określanie stawek) | 8419777862490735710 |
Flurry | 3376427960656545613 |
Fyber* * To źródło reklam jest używane do raportowania danych historycznych. | 4839637394546996422 |
i-mobile | 5208827440166355534 |
Improve Digital (określanie stawek) | 159382223051638006 |
Index Exchange (ustalanie stawek) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi (określanie stawek) | 6325663098072678541 |
InMobi Exchange (określanie stawek) | 5264320421916134407 |
IronSource | 6925240245545091930 |
ironSource Ads (licytowanie) | 1643326773739866623 |
Leadbolt | 2899150749497968595 |
Liftoff Monetize* * Przed 30 stycznia 2023 r. ta sieć nosiła nazwę „Vungle”. | 1953547073528090325 |
Liftoff Monetize (licytowanie)* * Przed 30 stycznia 2023 r. ta sieć nosiła nazwę „Vungle (licytowanie)”. | 4692500501762622185 |
LG U+AD | 18298738678491729107 |
LINE Ads Network | 3025503711505004547 |
Magnite DV+ (licytowanie) | 3993193775968767067 |
maio | 7505118203095108657 |
maio (określanie stawek) | 1343336733822567166 |
Media.net (określanie stawek) | 2127936450554446159 |
Zapośredniczone autoreklamy | 6060308706800320801 |
Meta Audience Network* * Do 6 czerwca 2022 r. ta sieć nosiła nazwę „Facebook Audience Network”. | 10568273599589928883 |
Meta Audience Network (licytowanie)* * Przed 6 czerwca 2022 r. ta sieć nosiła nazwę „Facebook Audience Network (licytowanie)”. | 11198165126854996598 |
Mintegral | 1357746574408896200 |
Mintegral (określanie stawek) | 6250601289653372374 |
MobFox (określanie stawek) | 3086513548163922365 |
MoPub (wycofane) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
Nexxen (określanie stawek)* * Przed 1 maja 2024 r. ta sieć nosiła nazwę „UnrulyX”. | 2831998725945605450 |
OneTag Exchange (ustalanie stawek) | 4873891452523427499 |
OpenX (określanie stawek) | 4918705482605678398 |
Pangle | 4069896914521993236 |
Pangle (określanie stawek) | 3525379893916449117 |
PubMatic (określanie stawek) | 3841544486172445473 |
Kampania z rezerwacją | 7068401028668408324 |
SK planet | 734341340207269415 |
Sharethrough (określanie stawek) | 5247944089976324188 |
Smaato (określanie stawek) | 3362360112145450544 |
Sonobi (określanie stawek) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy (określanie stawek) | 4692500501762622178 |
Tencent GDT | 7007906637038700218 |
TripleLift (określanie stawek) | 8332676245392738510 |
Unity Ads | 4970775877303683148 |
Unity Ads (określanie stawek) | 7069338991535737586 |
Verve Group (ustalanie stawek) | 5013176581647059185 |
Vpon | 1940957084538325905 |
Yieldmo (określanie stawek) | 4193081836471107579 |
YieldOne (określanie stawek) | 3154533971590234104 |
Zucks | 5506531810221735863 |
Nagradzanie użytkownika
Decydując, kiedy przyznać użytkownikowi nagrodę, musisz zachować równowagę między wygodą użytkownika a weryfikacją nagrody. Wywołania zwrotne po stronie serwera mogą docierać do systemów zewnętrznych z opóźnieniem. Dlatego zalecamy używanie wywołania zwrotnego po stronie klienta, aby natychmiast przyznawać użytkownikowi nagrodę, a jednocześnie weryfikować wszystkie nagrody po otrzymaniu wywołań zwrotnych po stronie serwera. Takie podejście zapewnia użytkownikom wygodę, a jednocześnie gwarantuje ważność przyznanych nagród.
W przypadku aplikacji, w których ważność nagrody ma kluczowe znaczenie (np. nagroda wpływa na ekonomię w grze), a opóźnienia w przyznawaniu nagród są dopuszczalne, najlepszym rozwiązaniem może być oczekiwanie na zweryfikowane wywołanie zwrotne po stronie serwera.
Dane niestandardowe
Aplikacje, które wymagają dodatkowych danych w wywołaniach zwrotnych weryfikacji po stronie serwera, powinny korzystać z funkcji danych niestandardowych w reklamach z nagrodą. Każda wartość ciągu znaków ustawiona w obiekcie reklamy z nagrodą jest przekazywana do parametru zapytania custom_data
wywołania zwrotnego SSV. Jeśli nie ustawiono wartości danych niestandardowych, wartość parametru zapytania custom_data
nie będzie obecna w wywołaniu zwrotnym SSV.
W poniższym przykładzie opcje SSV są ustawiane po wczytaniu reklamy z nagrodą:
Java
RewardedAd.load(MainActivity.this, "AD_UNIT_ID", 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, "AD_UNIT_ID", 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 } })
Jeśli chcesz ustawić niestandardowy ciąg znaków nagrody, musisz to zrobić przed wyświetleniem reklamy.
Ręczna weryfikacja weryfikacji reklam z nagrodą po stronie serwera
Poniżej opisujemy czynności wykonywane przez klasę RewardedAdsVerifier
w celu weryfikacji nagrodzonego SSV. Chociaż dołączone fragmenty kodu są napisane w języku Java i korzystają z biblioteki innej firmy Tink, możesz wykonać te czynności w wybranym języku, używając dowolnej biblioteki innej firmy, która obsługuje ECDSA.
Pobieranie kluczy publicznych
Aby zweryfikować wywołanie zwrotne SSV za nagrodę, potrzebujesz klucza publicznego udostępnionego przez AdMob.
Listę kluczy publicznych, które mają być używane do weryfikowania wywołań zwrotnych SSV dotyczących reklam z nagrodą, można pobrać z serwera kluczy AdMob. Lista kluczy publicznych jest podawana w formacie JSON podobnym do tego:
{
"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=="
},
],
}
Aby pobrać klucze publiczne, połącz się z serwerem kluczy AdMob i pobierz klucze. Poniższy kod wykonuje to zadanie i zapisuje reprezentację kluczy w formacie JSON w zmiennej 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();
}
Pamiętaj, że klucze publiczne są regularnie zmieniane. Otrzymasz e-maila z informacją o nadchodzącej rotacji. Jeśli buforujesz klucze publiczne, po otrzymaniu tego e-maila musisz je zaktualizować.
Po pobraniu kluczy publicznych należy je przeanalizować. Poniższa metoda parsePublicKeysJson
przyjmuje jako dane wejściowe ciąg znaków JSON, taki jak w przykładzie powyżej, i tworzy mapowanie wartości key_id
na klucze publiczne, które są hermetyzowane jako obiekty ECPublicKey
z biblioteki 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;
}
Uzyskiwanie treści do weryfikacji
Ostatnie 2 parametry zapytania w wywołaniach zwrotnych SSV z nagrodą to zawsze signature
i key_id,
w tej kolejności. Pozostałe parametry zapytania określają treść, która ma zostać zweryfikowana. Załóżmy, że AdMob jest skonfigurowany tak, aby wysyłać wywołania zwrotne dotyczące nagród na adres https://www.myserver.com/mypath
. Fragment kodu poniżej pokazuje przykład wywołania zwrotnego SSV z nagrodą, w którym wyróżniono treść do zweryfikowania.
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
Poniższy kod pokazuje, jak przeanalizować treść do zweryfikowania z adresu URL wywołania zwrotnego jako tablicę bajtów 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"));
Pobieranie podpisu i identyfikatora klucza z adresu URL wywołania zwrotnego
Korzystając z wartości queryString
z poprzedniego kroku, przeanalizuj parametry zapytania signature
i key_id
z adresu URL wywołania zwrotnego, jak pokazano poniżej:
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()));
Przeprowadzanie weryfikacji
Ostatnim krokiem jest zweryfikowanie treści adresu URL wywołania zwrotnego za pomocą odpowiedniego klucza publicznego. Pobierz mapowanie zwrócone przez metodę parsePublicKeysJson
i użyj parametru key_id
z adresu URL wywołania zwrotnego, aby uzyskać klucz publiczny z tego mapowania. Następnie zweryfikuj podpis za pomocą tego klucza publicznego. Te czynności są pokazane poniżej w metodzie 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);
}
}
Jeśli metoda zostanie wykonana bez zgłaszania wyjątku, adres URL wywołania zwrotnego został zweryfikowany.
Najczęstsze pytania
- Czy mogę buforować klucz publiczny udostępniany przez serwer kluczy AdMob?
- Zalecamy zapisywanie w pamięci podręcznej klucza publicznego udostępnianego przez serwer kluczy AdMob, aby zmniejszyć liczbę operacji wymaganych do weryfikacji wywołań zwrotnych SSV. Pamiętaj jednak, że klucze publiczne są regularnie zmieniane i nie powinny być przechowywane w pamięci podręcznej dłużej niż 24 godziny.
- Jak często klucze publiczne udostępniane przez serwer kluczy AdMob są zmieniane?
- Klucze publiczne udostępniane przez serwer kluczy AdMob są zmieniane zgodnie z różnym harmonogramem. Aby weryfikacja wywołań zwrotnych SSV nadal działała zgodnie z założeniami, klucze publiczne nie powinny być przechowywane w pamięci podręcznej dłużej niż 24 godziny.
- Co się stanie, jeśli nie będzie można się połączyć z moim serwerem?
- Google oczekuje kodu stanu odpowiedzi
HTTP 200 OK
w przypadku wywołań zwrotnych SSV. Jeśli nie można nawiązać połączenia z serwerem lub nie zwraca on oczekiwanej odpowiedzi, Google podejmie do 5 prób wysłania wywołań zwrotnych SSV w odstępach 1-sekundowych. - Jak mogę sprawdzić, czy wywołania zwrotne SSV pochodzą z Google?
- Używaj odwrotnego wyszukiwania DNS, aby sprawdzać, czy wywołania zwrotne SSV pochodzą z Google.