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 reklamą pełnoekranową z nagrodą. Wywołania zwrotne w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą stanowią dodatkową warstwę ochrony przed podszywaniem się pod wywołania zwrotne po stronie klienta w celu przyznania nagród użytkownikom.
Z tego przewodnika dowiesz się, jak weryfikować wywołania zwrotne w ramach weryfikacji po stronie serwera (SSV) w przypadku 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 też użyć dowolnej biblioteki innej firmy, która obsługuje algorytm ECDSA. Możesz też przetestować swój serwer za pomocą narzędzia do testowania w interfejsie AdMob.
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 Tink Java Apps na GitHubie
zawiera
RewardedAdsVerifier
klasę pomocniczą, która zmniejsza ilość kodu wymaganego do weryfikacji wywołania zwrotnego w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą.
Użycie tej klasy umożliwia weryfikację adresu URL wywołania zwrotnego za pomocą tego 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łoszenia wyjątku, adres URL wywołania zwrotnego zostanie zweryfikowany. W sekcji Przyznawanie nagród użytkownikom
znajdziesz sprawdzone metody dotyczące tego, kiedy należy przyznawać nagrody użytkownikom. Aby dowiedzieć się, jakie kroki wykonuje ta klasa w celu weryfikacji wywołań zwrotnych w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą, przeczytaj sekcję Ręczna weryfikacja wywołań zwrotnych w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą.
Parametry wywołania zwrotnego w ramach weryfikacji po stronie serwera (SSV)
Wywołania zwrotne w ramach weryfikacji po stronie serwera (SSV) zawierają parametry zapytania, które opisują 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, z którego pochodzi ta reklama. Nazwy źródeł reklam odpowiadające wartościom identyfikatorów znajdziesz w sekcji Identyfikatory źródeł reklam. | 1953547073528090325 |
| ad_unit | Identyfikator jednostki reklamowej AdMob, która została użyta do wysłania żądania reklamy z nagrodą. | 2747237135 |
| custom_data | Ciąg znaków danych niestandardowych podany przez
customRewardString.
Jeśli aplikacja nie poda ciągu znaków danych niestandardowych, wartość tego parametru zapytania nie będzie obecna w wywołaniu zwrotnym w ramach weryfikacji po stronie serwera (SSV). |
SAMPLE_CUSTOM_DATA_STRING |
| key_id | Klucz, który ma być używany do weryfikacji wywołania zwrotnego w ramach weryfikacji po stronie serwera (SSV). Ta wartość jest mapowana na klucz publiczny udostępniony 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 |
| signature | Podpis wywołania zwrotnego w ramach weryfikacji po stronie serwera (SSV) wygenerowany przez AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
| timestamp | Sygnatura czasowa momentu przyznania nagrody użytkownikowi w formacie czasu epoki w milisekundach. | 1507770365237823 |
| transaction_id | Unikalny identyfikator zakodowany w systemie szesnastkowym każdego zdarzenia przyznania nagrody wygenerowanego przez AdMob. | 18fa792de1bca816048293fc71035638 |
| user_id | Identyfikator użytkownika podany przez
userIdentifier.
Jeśli aplikacja nie poda identyfikatora użytkownika, ten parametr zapytania nie będzie obecny w wywołaniu zwrotnym w ramach weryfikacji po stronie serwera (SSV). |
1234567 |
Identyfikatory źródeł 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ć nazywała się „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 (określanie stawek) | 4100650709078789802 |
| InMobi | 7681903010231960328 |
| InMobi (określanie stawek) | 6325663098072678541 |
| InMobi Exchange (określanie stawek) | 5264320421916134407 |
| IronSource | 6925240245545091930 |
| ironSource Ads (określanie stawek) | 1643326773739866623 |
| Leadbolt | 2899150749497968595 |
| Liftoff Monetize* * Przed 30 stycznia 2023 r. ta sieć nazywała się „Vungle”. | 1953547073528090325 |
| Liftoff Monetize (określanie stawek)* * Przed 30 stycznia 2023 r. ta sieć nazywała się „Vungle (określanie stawek)”. | 4692500501762622185 |
| LG U+AD | 18298738678491729107 |
| LINE Ads Network | 3025503711505004547 |
| Magnite DV+ (określanie stawek) | 3993193775968767067 |
| maio | 7505118203095108657 |
| maio (określanie stawek) | 1343336733822567166 |
| Media.net (określanie stawek) | 2127936450554446159 |
| Zapośredniczone autoreklamy | 6060308706800320801 |
| Meta Audience Network* * Przed 6 czerwca 2022 r. ta sieć nazywała się "Facebook Audience Network". | 10568273599589928883 |
| Meta Audience Network (określanie stawek)* * Przed 6 czerwca 2022 r. ta sieć nazywała się "Facebook Audience Network (określanie stawek)". | 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ć nazywała się „UnrulyX”. | 2831998725945605450 |
| OneTag Exchange (określanie 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 (określanie stawek) | 5013176581647059185 |
| Vpon | 1940957084538325905 |
| Yieldmo (określanie stawek) | 4193081836471107579 |
| YieldOne (określanie stawek) | 3154533971590234104 |
| Zucks | 5506531810221735863 |
Przyznawanie nagród użytkownikom
Przy podejmowaniu decyzji o tym, kiedy przyznać nagrodę użytkownikowi, ważne jest, aby 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 do natychmiastowego przyznawania nagród użytkownikom, a jednocześnie przeprowadzanie weryfikacji wszystkich nagród po otrzymaniu wywołań zwrotnych po stronie serwera. Takie podejście zapewnia wygodę użytkowników i 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) i opóźnienia w przyznawaniu nagród są dopuszczalne, najlepszym rozwiązaniem może być poczekanie na zweryfikowane wywołanie zwrotne po stronie serwera.
Dane niestandardowe
Aplikacje, które wymagają dodatkowych danych w wywołaniach zwrotnych w ramach 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 w ramach weryfikacji po stronie serwera (SSV). Jeśli nie ustawisz wartości danych niestandardowych, wartość parametru zapytania custom_data nie będzie obecna w wywołaniu zwrotnym w ramach weryfikacji po stronie serwera (SSV).
Poniższy przykład pokazuje, jak ustawić opcje weryfikacji po stronie serwera (SSV) po wczytaniu reklamy z nagrodą:
Swift
RewardedAd.load(with:"AD_UNIT_ID", request: request, completionHandler: { [self] ad, error in if let error != error { rewardedAd = ad let options = ServerSideVerificationOptions() options.customRewardString = "SAMPLE_CUSTOM_DATA_STRING" rewardedAd.serverSideVerificationOptions = options } })
Objective-C
GADRequest *request = [GADRequest request]; [GADRewardedAd loadWithAdUnitID:@"AD_UNIT_ID" request:request completionHandler:^(GADRewardedAd *ad, NSError *error) { if (error) { // Handle Error return; } self.rewardedAd = ad; GADServerSideVerificationOptions *options = [[GADServerSideVerificationOptions alloc] init]; options.customRewardString = @"SAMPLE_CUSTOM_DATA_STRING"; ad.serverSideVerificationOptions = options; }];
Ręczna weryfikacja wywołań zwrotnych w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą
Poniżej znajdziesz opis czynności wykonywanych przez klasę RewardedAdsVerifier w celu weryfikacji wywołania zwrotnego w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą. Chociaż fragmenty kodu są napisane w języku Java i
korzystają z biblioteki innej firmy Tink, możesz zaimplementować te kroki w
wybranym języku, używając dowolnej biblioteki innej firmy, która obsługuje
ECDSA.
Pobieranie kluczy publicznych
Aby zweryfikować wywołanie zwrotne w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą, potrzebujesz klucza publicznego udostępnionego przez AdMob.
Listę kluczy publicznych, które mają być używane do weryfikacji wywołań zwrotnych w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą, można pobrać z serwera kluczy AdMob. Lista kluczy publicznych jest udostępniana w postaci reprezentacji JSON w formacie 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ę JSON kluczy 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 zbliżającej się zmianie. Jeśli przechowujesz klucze publiczne w pamięci podręcznej, po otrzymaniu tego e-maila zaktualizuj klucze.
Po pobraniu kluczy publicznych należy je przeanalizować. Poniższa metoda parsePublicKeysJson przyjmuje jako dane wejściowe ciąg znaków JSON, taki jak przykład 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;
}
Pobieranie treści do zweryfikowania
Ostatnie 2 parametry zapytania wywołań zwrotnych w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą to zawsze signature
i key_id, w tej kolejności. Pozostałe parametry zapytania określają treść do zweryfikowania. Załóżmy, że skonfigurowano AdMob tak, aby wysyłał wywołania zwrotne dotyczące nagród na adres https://www.myserver.com/mypath. Poniższy fragment kodu przedstawia przykład wywołania zwrotnego w ramach weryfikacji po stronie serwera (SSV) w przypadku reklam z nagrodą z wyróżnioną treścią 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
Używając wartości queryString z poprzedniego kroku, przeanalizuj parametry zapytania signature i key_id z adresu URL wywołania zwrotnego w sposób pokazany 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 kroki 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łoszenia wyjątku, adres URL wywołania zwrotnego zostanie zweryfikowany.
Najczęstsze pytania
- Czy mogę przechowywać w pamięci podręcznej klucz publiczny udostępniony przez serwer kluczy AdMob?
- Zalecamy przechowywanie w pamięci podręcznej klucza publicznego udostępnionego przez serwer kluczy AdMob, aby zmniejszyć liczbę operacji wymaganych do weryfikacji wywołań zwrotnych w ramach weryfikacji po stronie serwera (SSV). Pamiętaj jednak, że klucze publiczne są regularnie zmieniane i nie należy ich przechowywać w pamięci podręcznej dłużej niż 24 godziny.
- Jak często są zmieniane klucze publiczne udostępniane przez serwer kluczy AdMob?
- Klucze publiczne udostępniane przez serwer kluczy AdMob są zmieniane według zmiennego harmonogramu. Aby mieć pewność, że weryfikacja wywołań zwrotnych w ramach weryfikacji po stronie serwera (SSV) nadal działa zgodnie z oczekiwaniami, 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 nawiązać połączenia z moim serwerem?
- W przypadku wywołań zwrotnych w ramach weryfikacji po stronie serwera (SSV) Google oczekuje kodu stanu odpowiedzi
HTTP 200 OK. Jeśli nie będzie można nawiązać połączenia z Twoim serwerem lub nie zwróci on oczekiwanej odpowiedzi, Google podejmie do 5 prób ponownego wysłania wywołań zwrotnych w ramach weryfikacji po stronie serwera (SSV) w odstępach 1-sekundowych. - Jak mogę sprawdzić, czy wywołania zwrotne w ramach weryfikacji po stronie serwera (SSV) pochodzą z Google?
- Aby sprawdzić, czy wywołania zwrotne w ramach weryfikacji po stronie serwera (SSV) pochodzą z Google, użyj odwrotnego wyszukiwania DNS.