Wywołania zwrotne weryfikacji po stronie serwera to żądania adresów URL z parametrami zapytania rozszerzonymi przez Google. Są one wysyłane przez Google do systemu zewnętrznego, aby powiadomić go, że użytkownik powinien zostać nagradzany za interakcję z reklamą pełnoekranową z nagrodą lub reklamą pełnoekranową z nagrodą. Wywołania zwrotne z nagrodą SSV (weryfikacja po stronie serwera) zapewniają dodatkową warstwę ochrony przed podszywaniem się pod wywołania zwrotne po stronie klienta w celu nagradzania użytkowników.
Z tego przewodnika dowiesz się, jak zweryfikować wywołania zwrotne z nagrodą SSV z nagrodą przy użyciu zewnętrznej biblioteki kryptograficznej Tink Java Apps, aby upewnić się, że parametry zapytania w wywołaniu zwrotnym mają prawidłowe wartości. Mimo że na potrzeby tego przewodnika wykorzystywany jest Tink, możesz użyć dowolnej biblioteki zewnętrznej, która obsługuje ECDSA. Możesz też przetestować swój serwer za pomocą narzędzia do testowania w interfejsie AdMob.
Zapoznaj się z tym w pełni działającym przykładem z użyciem narzędzia Java spring-boot.
Wymagania wstępne
Zintegruj reklamy z nagrodą ze swoją aplikacją mobilną za pomocą pakietu SDK do reklam mobilnych Google w wersji pakiet SDK do reklam mobilnych Google w wersji 7.28.0 lub nowszej.
Włącz w swojej jednostce reklamowej weryfikację z nagrodą po stronie serwera.
Korzystanie z interfejsu RewardedAdsVerifier z biblioteki Tink Java Apps
Repozytorium aplikacji Tink Java na GitHubie zawiera klasę pomocniczą RewardedAdsVerifier
, która zmniejsza ilość kodu wymaganego do weryfikacji wywołania zwrotnego SSV z nagrodą.
Użycie tej klasy umożliwia zweryfikowanie adresu URL wywołania zwrotnego za pomocą podanego niżej 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 został zweryfikowany. Sekcja Nagradzanie użytkowników zawiera szczegółowe informacje na temat sprawdzonych metod dotyczących tego, kiedy użytkownicy powinni być nagradzani. Informacje o czynnościach wykonywanych przez tę klasę w celu weryfikacji wywołań zwrotnych SSV z nagrodą znajdziesz w sekcji Ręczna weryfikacja weryfikacji reklam z nagrodą.
Parametry wywołania zwrotnego SSV
Wywołania zwrotne weryfikacji po stronie serwera zawierają parametry zapytania opisujące interakcję z reklamą z nagrodą. Poniżej znajdziesz nazwy, opisy i przykładowe wartości parametrów. Parametry są wysyłane w kolejności alfabetycznej.
Nazwa parametru | Opis | Przykładowa wartość |
---|---|---|
ad_network | Identyfikator źródła reklam, które zrealizowało wyświetlenie tej reklamy. Nazwy źródeł reklam odpowiadające wartościom identyfikatorów znajdziesz w sekcji Identyfikatory źródeł reklam. | 1953547073528090325 |
ad_unit | Identyfikator jednostki reklamowej AdMob użytej do żądania reklamy z nagrodą. | 2747237135 |
custom_data | Niestandardowy ciąg danych podany przez:
customRewardString
.
Jeśli aplikacja nie poda żadnego niestandardowego ciągu danych, wartość tego parametru zapytania nie będzie dostępna w wywołaniu zwrotnym SSV. |
SAMPLE_CUSTOM_DATA_STRING |
key_id | Klucz, który ma być używany do weryfikacji wywołania zwrotnego SSV. Ta wartość jest mapowana na klucz publiczny dostarczony przez serwer kluczy AdMob. | 1234567890 |
reward_amount | Kwota 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 wygenerowanego przez AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
sygnatura czasowa | Sygnatura czasowa, kiedy użytkownik otrzymał nagrodę jako czas epoki w ms. | 1507770365237823 |
transaction_id | Unikalny identyfikator zakodowany szesnastkowo dla 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, parametr zapytania nie będzie widoczny w wywołaniu zwrotnym SSV. |
1234567 |
Identyfikatory źródeł reklam
Nazwy i identyfikatory źródeł reklam
Nazwa źródła reklamy | Identyfikator źródła reklam |
---|---|
Aarki (określanie stawek) | 5240798063227064260 |
Generowanie reklam (ustalanie stawek) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony (poza pakietem SDK) (określanie stawek) | 4600416542059544716 |
AdColony (określanie stawek) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
Sieć AdMob | 5450213213286189855 |
ADResult | 10593873382626181482 |
Reklama AMo | 17253994435944008978 |
Applovin, | 1063618907739174004 |
Applovin (określanie stawek) | 1328079684332308356 |
Chartboost | 2873236629771172317 |
Platforma czekolady (określanie stawek) | 6432849193975106527 |
Wiele kanałów (MdotM) | 9372067028804390441 |
Zdarzenie niestandardowe | 18351550913290782395 |
DT Exchange* * Przed 21 września 2022 r. sieć nosiła nazwę „Fyber Marketplace”. | 2179455223494392917 |
EMX (określanie stawek) | 8497809869790333482 |
Zmienność (ustalanie stawek) | 8419777862490735710 |
Lekkie | 3376427960656545613 |
Fyber* * To źródło reklam służy do raportowania historycznego. | 4839637394546996422 |
i-mobile | 5208827440166355534 |
Ulepszaj reklamy cyfrowe (ustalanie stawek) | 159382223051638006 |
Index Exchange (ustalanie stawek) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi (określanie stawek) | 6325663098072678541 |
IronSource | 6925240245545091930 |
Reklamy ironSource (ustalanie stawek) | 1643326773739866623 |
Leadbolt | 2899150749497968595 |
LG U+AD | 18298738678491729107 |
Sieć reklamowa LINE | 3025503711505004547 |
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. sieć nosiła nazwę „Facebook Audience Network”. | 10568273599589928883 |
Meta Audience Network (określanie stawek)* * Przed 6 czerwca 2022 r. sieć nosiła nazwę „Facebook Audience Network (określanie stawek)”. | 11198165126854996598 |
Mintegral | 1357746574408896200 |
Mintegral (określanie stawek) | 6250601289653372374 |
MobFox | 8079529624516381459 |
MobFox (określanie stawek) | 3086513548163922365 |
MoPub (wycofane) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
Nexxen (określanie stawek)* * Przed 1 maja 2024 r. sieć ta nazywała się „UnrulyX”. | 2831998725945605450 |
ONE by AOL (Millennial Media) | 6101072188699264581 |
ONE by AOL (Nexage) | 3224789793037044399 |
OneTag Exchange (ustalanie stawek) | 4873891452523427499 |
OpenX (określanie stawek) | 4918705482605678398 |
Pangle (określanie stawek) | 3525379893916449117 |
PubMatic (określanie stawek) | 3841544486172445473 |
Kampania z rezerwacją | 7068401028668408324 |
RhythmOne (określanie stawek) | 2831998725945605450 |
Rubicon (określanie stawek) | 3993193775968767067 |
Planeta SK | 734341340207269415 |
Współczynnik udziału (określanie stawek) | 5247944089976324188 |
Smaato (określanie stawek) | 3362360112145450544 |
Równy (określanie stawek)* * Do 12 stycznia 2023 r. sieć ta nazywała się „Smart Adserver”. | 5970199210771591442 |
Sonobi (określanie stawek) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy (określanie stawek) | 4692500501762622178 |
Tencent (GDT) | 7007906637038700218 |
TripleLift (określanie stawek) | 8332676245392738510 |
Reklamy Unity | 4970775877303683148 |
Reklamy Unity (określanie stawek) | 7069338991535737586 |
Verizon Media, | 7360851262951344112 |
Grupa Verve (określanie stawek) | 5013176581647059185 |
Vpon | 1940957084538325905 |
Liftoff – zarabianie* * Przed 30 stycznia 2023 r. sieć ta nazywała się „Vungle”. | 1953547073528090325 |
Liftoff Monetize (określanie stawek)* * Przed 30 stycznia 2023 r. sieć ta nosiła nazwę „Vungle (określanie stawek)”. | 4692500501762622185 |
Yieldmo (określanie stawek) | 4193081836471107579 |
YieldOne (określanie stawek) | 3154533971590234104 |
Kaczki | 5506531810221735863 |
Nagradzanie użytkowników
Decydując, kiedy wynagrodzić użytkownika, należy wziąć pod uwagę wrażenia użytkownika i weryfikację nagród. Wywołania zwrotne po stronie serwera mogą docierać z opóźnieniem, zanim dotrą do systemów zewnętrznych. Dlatego zalecaną sprawdzoną metodą jest użycie wywołania zwrotnego po stronie klienta do natychmiastowego wynagrodzenia użytkownika oraz walidację wszystkich nagród po otrzymaniu wywołań zwrotnych po stronie serwera. Takie podejście zapewnia pozytywne wrażenia użytkowników, a jednocześnie zapewnia prawidłowość przyznanych nagród.
Jednak w przypadku aplikacji, w których okres ważności nagrody ma kluczowe znaczenie (np. gdy nagroda wpływa na ekonomię w grze), opóźnienia w przyznawaniu nagród są dopuszczalne. Lepszym rozwiązaniem może być oczekiwanie na zweryfikowane wywołanie zwrotne po stronie serwera.
Dane niestandardowe
Aplikacje, które w wywołaniach zwrotnych weryfikacji po stronie serwera wymagają dodatkowych danych, powinny korzystać z niestandardowych danych w reklamach z nagrodą. Każda wartość ciągu znaków ustawiona w obiekcie reklamy z nagrodą jest przekazywana do parametru zapytania custom_data
w wywołaniu zwrotnym SSV. Jeśli nie ustawisz żadnej wartości danych niestandardowych, wartość parametru zapytania custom_data
nie będzie widoczna w wywołaniu zwrotnym SSV.
Poniższy przykładowy kod pokazuje, jak ustawić opcje SSV po wczytaniu reklamy z nagrodą.
Swift
GADRewardedAd.load(withAdUnitID:"ca-app-pub-3940256099942544/1712485313", request: request, completionHandler: { [self] ad, error in if let error != error { rewardedAd = ad let options = GADServerSideVerificationOptions() options.customRewardString = "SAMPLE_CUSTOM_DATA_STRING" rewardedAd.serverSideVerificationOptions = options }
Objective-C
GADRequest *request = [GADRequest request]; [GADRewardedAd loadWithAdUnitID:@"ca-app-pub-3940256099942544/1712485313" 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 weryfikacji reklam z nagrodą
Poniżej znajdziesz czynności wykonywane przez klasę RewardedAdsVerifier
w celu weryfikacji SSV z nagrodą. Chociaż dołączone fragmenty kodu są w Javie i wykorzystują zewnętrzną bibliotekę Tink, możesz wykonać te kroki w wybranym języku, używając dowolnej biblioteki zewnętrznej, która obsługuje ECDSA.
Pobierz klucze publiczne
Aby zweryfikować wywołanie zwrotne SSV z nagrodą, potrzebujesz klucza publicznego dostarczonego przez AdMob.
Listę kluczy publicznych używanych do weryfikacji wywołań zwrotnych SSV z nagrodą możesz 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ę kluczy 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 poddawane rotacji. Otrzymasz e-maila z informacją o nadchodzącej rotacji. Jeśli przechowujesz klucze publiczne w pamięci podręcznej, zaktualizuj je po otrzymaniu tego e-maila.
Po pobraniu klucze publiczne trzeba przeanalizować. Poniższa metoda parsePublicKeysJson
przyjmuje jako dane wejściowe ciąg JSON, jak w przykładzie powyżej, i tworzy mapowanie z wartości key_id
na klucze publiczne, które są zamknięte 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;
}
Przesyłanie treści do weryfikacji
Dwa ostatnie parametry zapytań w wywołaniach zwrotnych SSV z nagrodą to zawsze signature
i key_id,
w tej kolejności. Pozostałe parametry zapytania określają treść do zweryfikowania. Załóżmy, że masz skonfigurowane w AdMob wysyłanie wywołań zwrotnych z nagrodą do https://www.myserver.com/mypath
. Fragment kodu poniżej przedstawia przykładowe wywołanie zwrotne SSV z nagrodą z zaznaczoną treścią do weryfikacji.
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 analizować treści, które mają zostać zweryfikowane z adresu URL wywołania zwrotnego, jako tablicę 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"));
Uzyskiwanie podpisu i parametru key_id 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 w podany niżej sposób:
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()));
Przeprowadź weryfikację
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. Potem sprawdź podpis za pomocą tego klucza publicznego. Poniżej w metodzie verify
pokazano te czynności.
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 został zweryfikowany.
Najczęstsze pytania
- Czy mogę zapisać w pamięci podręcznej klucz publiczny dostarczony przez serwer kluczy AdMob?
- Zalecamy zapisywanie klucza publicznego dostarczonego przez serwer kluczy AdMob w pamięci podręcznej, aby zmniejszyć liczbę operacji wymaganych do weryfikacji wywołań zwrotnych SSV. Pamiętaj jednak, że klucze publiczne są regularnie poddawane rotacji i nie powinny być przechowywane w pamięci podręcznej przez ponad 24 godziny.
- Jak często poddawana jest rotacja kluczy publicznych dostarczanych przez serwer kluczy AdMob?
- Klucze publiczne udostępniane przez serwer kluczy AdMob są poddawane rotacji według zmiennej harmonogramu. Aby weryfikacja wywołań zwrotnych SSV nadal działał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 połączyć się z moim serwerem?
- W przypadku wywołań zwrotnych SSV Google oczekuje kodu odpowiedzi stanu powodzenia
HTTP 200 OK
. Jeśli z serwerem nie można się połączyć lub nie odpowiada oczekiwanej odpowiedzi, Google spróbuje ponownie wysłać wywołania zwrotne SSV do 5 razy w 1-sekundowych odstępach. - Jak sprawdzić, czy wywołania zwrotne SSV pochodzą z Google?
- Użyj wstecznego wyszukiwania DNS, aby sprawdzić, czy wywołania zwrotne SSV pochodzą od Google.