Wywołania zwrotne w ramach weryfikacji po stronie serwera to żądania adresów URL z poszerzonymi parametrami zapytań, które są wysyłane przez Google do systemów zewnętrznych i informują nas, że użytkownik powinien otrzymać nagrodę za interakcję z reklamą pełnoekranową z nagrodą. Wywołania zwrotne z nagrodą SSV (weryfikacja po stronie serwera) stanowią dodatkową warstwę ochrony przed podszywaniem się pod klienta po stronie klienta, aby nagradzać użytkowników.
W tym przewodniku pokazujemy, jak zweryfikować wywołania zwrotne SSV z nagrodą za pomocą biblioteki kryptograficznej Tink Java Apps, aby zapewnić poprawne parametry zapytania w wywołaniach zwrotnych. Mimo że na potrzeby tego przewodnika do tego celu używany jest Tink, masz możliwość korzystania z dowolnej biblioteki zewnętrznej, która obsługuje ECDSA. Możesz też przetestować serwer za pomocą narzędzia do testowania w interfejsie AdMob.
Zapoznaj się z tym w pełni działającym przykładem wykorzystującym sprężynowe oprogramowanie Java.
Wymagania wstępne
Zintegruj reklamy z nagrodą z aplikacją mobilną, używając pakietu SDK do reklam mobilnych Google w wersji Wersja 7.28.0 lub nowsza pakietu SDK do reklam mobilnych Google.
Włącz weryfikację po stronie serwera z nagrodą w jednostce reklamowej.
Używanie funkcji RewardedAdsVerifier z biblioteki aplikacji Tink Java
Repozytorium Tink Java Apps zawiera klasę pomocniczą RewardedAdsVerifier
umożliwiającą zmniejszenie kodu wymaganego do wywołania wywołania zwrotnego reklamy z nagrodą.
Użycie tej klasy pozwala zweryfikować adres URL wywołania zwrotnego o poniższym kodzie.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
Jeśli metoda verify()
jest uruchamiana bez zgłaszania wyjątku, adres URL wywołania zwrotnego został zweryfikowany. Sekcja Nagradzanie użytkowników zawiera sprawdzone metody dotyczące tego, kiedy użytkownicy powinni otrzymać nagrodę. Zestawienie działań wykonanych w ramach tej weryfikacji pozwala zweryfikować wywołania zwrotne SSV z nagrodą. Możesz zapoznać się z sekcją Weryfikacja ręczna z nagrodą SSV.
Parametry wywołania zwrotnego SSV
Wywołania zwrotne w ramach weryfikacji po stronie serwera zawierają parametry zapytania opisujące interakcję z reklamą. Nazwy i opisy parametrów oraz przykładowe wartości są podane poniżej. Parametry są przesyłane w kolejności alfabetycznej.
Nazwa parametru | opis, | Przykładowa wartość |
---|---|---|
sieć_reklamowa | Identyfikator źródła reklamy, który ją wyświetlił. Nazwy źródeł reklam odpowiadające wartościom identyfikatora znajdziesz w sekcji Identyfikatory źródeł reklam. | 1953547073528090325 |
ad_unit, | Identyfikator jednostki reklamowej AdMob użyty do wysłania żądania reklamy z nagrodą. | 2747237135 |
dane_niestandardowe | Niestandardowy ciąg danych podany przez
customRewardString
.
Jeśli aplikacja nie poda żadnego niestandardowego ciągu danych, ta wartość parametru zapytania nie będzie występowała w wywołaniu zwrotnym SSV. |
SAMPLE_CUSTOM_DATA_STRING |
identyfikator_klucza | Klucz używany do weryfikowania wywołania zwrotnego SSV. Ta wartość jest mapowana na klucz publiczny udostępniony przez serwer kluczy AdMob. | 1234567890 |
kwota_nagrody | Kwota nagrody określona w ustawieniach jednostki reklamowej. | 5 |
element_nagrody | Nagroda, zgodnie z ustawieniami jednostki reklamowej. | monety |
podpis | Podpis wywołania zwrotnego SSV wygenerowany przez AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
sygnatura czasowa | Sygnatura czasowa wynagrodzenia użytkownika jako czas epoki w ms. | 1507770365237823 |
transaction_id | Unikalny zakodowany szesnastkowo identyfikator 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 występował w wywołaniu zwrotnym SSV. |
1234567 |
Identyfikatory źródeł reklam
Nazwy i identyfikatory źródeł reklam
Ad source name | Ad source ID |
---|---|
Aarki (bidding) | 5240798063227064260 |
Ad Generation (bidding) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony (non-SDK) (bidding) | 4600416542059544716 |
AdColony (bidding) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
AdMob Network | 5450213213286189855 |
ADResult | 10593873382626181482 |
AMoAd | 17253994435944008978 |
Applovin | 1063618907739174004 |
Applovin (bidding) | 1328079684332308356 |
Chartboost | 2873236629771172317 |
Chocolate Platform (bidding) | 6432849193975106527 |
CrossChannel (MdotM) | 9372067028804390441 |
Custom Event | 18351550913290782395 |
DT Exchange Prior to September 21, 2022, this network was called "Fyber". | 4839637394546996422 |
Fluct (bidding) | 8419777862490735710 |
Flurry | 3376427960656545613 |
i-mobile | 5208827440166355534 |
Improve Digital (bidding) | 159382223051638006 |
Index Exchange (bidding) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi (bidding) | 6325663098072678541 |
IronSource | 6925240245545091930 |
Leadbolt | 2899150749497968595 |
LG U+AD | 18298738678491729107 |
maio | 7505118203095108657 |
maio (bidding) | 1343336733822567166 |
Media.net (bidding) | 2127936450554446159 |
Mediated house ads | 6060308706800320801 |
Meta Audience Network Prior to June 6, 2022, this network was called the "Facebook Audience Network". | 10568273599589928883 |
Meta Audience Network (bidding) Prior to June 6, 2022, this network was called the "Facebook Audience Network (bidding)". | 11198165126854996598 |
MobFox | 8079529624516381459 |
MoPub (deprecated) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
ONE by AOL (Millennial Media) | 6101072188699264581 |
ONE by AOL (Nexage) | 3224789793037044399 |
OpenX (bidding) | 4918705482605678398 |
Pangle (bidding) | 3525379893916449117 |
PubMatic (bidding) | 3841544486172445473 |
Reservation campaign | 7068401028668408324 |
RhythmOne (bidding) | 2831998725945605450 |
Rubicon (bidding) | 3993193775968767067 |
SK planet | 734341340207269415 |
Sharethrough (bidding) | 5247944089976324188 |
Smaato (bidding) | 3362360112145450544 |
Equativ (bidding)* * Prior to January 12, 2023, this network was called "Smart Adserver". | 5970199210771591442 |
Sonobi (bidding) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy (bidding) | 4692500501762622178 |
Tencent GDT | 7007906637038700218 |
TripleLift (bidding) | 8332676245392738510 |
Unity Ads | 4970775877303683148 |
UnrulyX (bidding) | 2831998725945605450 |
Verizon Media | 7360851262951344112 |
Vpon | 1940957084538325905 |
Liftoff Monetize* * Prior to January 30, 2023, this network was called "Vungle". | 1953547073528090325 |
Liftoff Monetize (bidding)* * Prior to January 30, 2023, this network was called "Vungle". | 4692500501762622185 |
Yieldmo (bidding) | 4193081836471107579 |
YieldOne (bidding) | 3154533971590234104 |
Zucks | 5506531810221735863 |
Nagradzanie użytkowników
Ważne jest zachowanie równowagi między wrażeniami użytkownika a weryfikacją nagród podczas podejmowania decyzji o nagrodzie dla użytkownika. Mogą wystąpić opóźnienia w wywołaniach po stronie serwera przed uzyskaniem dostępu do systemów zewnętrznych. Z tego powodu zalecaną metodą jest używanie wywołania zwrotnego po stronie klienta w celu natychmiastowego nagradzania użytkownika, a jednocześnie sprawdzanie wszystkich nagród po otrzymaniu wywołań zwrotnych po stronie serwera. Takie podejście zapewnia użytkownikom dobre wrażenia, a jednocześnie zapewnia korzyści przyznawane nagrody.
W przypadku aplikacji, w których ważność nagrody ma kluczowe znaczenie (np. nagroda wpływa na gospodarkę gry w grze), a opóźnienia w realizacji nagród są dopuszczalne, czas oczekiwania na weryfikację po stronie serwera może być najlepszym podejściem.
Dane niestandardowe
Aplikacje, które wymagają dodatkowych danych w wywołaniach zwrotnych po stronie serwera, powinny używać funkcji danych niestandardowych reklam z nagrodą. Każda wartość ciągu ustawiona w obiekcie reklamy z nagrodą jest przekazywana do parametru zapytania custom_data
wywołania zwrotnego SSV. Jeśli nie ustawisz żadnej niestandardowej wartości danych, w wywołaniu zwrotnym SSV nie będzie wartości parametru zapytania custom_data
.
Poniższy 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 SSV z nagrodą
Czynności wykonywane przez klasę RewardedAdsVerifier
w celu zweryfikowania SSV z nagrodą można znaleźć poniżej. Uwzględnione fragmenty kodu są w języku Java i korzystają z biblioteki zewnętrznej Tink, ale możesz wykonać te czynności w wybranym przez siebie języku przy użyciu 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.
Lista kluczy publicznych używanych do weryfikowania wywołań zwrotnych SSV z nagrodą można pobrać z serwera kluczy AdMob. Lista kluczy publicznych jest podana w formacie 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. Ten kod wykonuje to zadanie i zapisuje przedstawienie kluczy w zmiennej 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 rotowane. Otrzymasz e-maila z informacją o nadchodzącej rotacji. Jeśli buforujesz klucze publiczne, zaktualizuj je po otrzymaniu tego e-maila.
Po pobraniu kluczy publicznych trzeba je przeanalizować. Poniższa metoda parsePublicKeysJson
pobiera tekst w postaci ciągu JSON (jak w powyższym przykładzie) i tworzy mapowanie z wartości key_id
do kluczy publicznych, 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;
}
Pobieranie treści do weryfikacji
Ostatnie 2 parametry zapytania z odwołaniami do reklam z nagrodą SSV mają zawsze wartość signature
i key_id,
w tej kolejności. Pozostałe parametry zapytania określają zawartość do zweryfikowania. Załóżmy, że masz skonfigurowane w AdMob wysyłanie wywołań zwrotnych do https://www.myserver.com/mypath
. Fragment kodu poniżej przedstawia przykładowe wywołanie zwrotne reklamy SSV z wyróżnioną treścią.
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ć zawartość weryfikowaną z adresu URL wywołania zwrotnego jako tablicę bajtową 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"));
Pobierz podpis i key_id z adresu URL wywołania zwrotnego
Przeanalizuj parametry zapytania signature
i key_id
z adresu URL wywołania zwrotnego, używając wartości queryString
z poprzedniego kroku, 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()));
Przeprowadź weryfikację
Ostatnim krokiem jest sprawdzenie treści adresu URL wywołania zwrotnego za pomocą odpowiedniego klucza publicznego. Wykorzystaj mapowanie zwrócone w metodzie parsePublicKeysJson
i użyj parametru key_id
z adresu URL wywołania zwrotnego, aby uzyskać klucz publiczny z mapowania. Następnie zweryfikuj podpis przy użyciu 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 jest wykonywana bez zgłaszania wyjątku, adres URL wywołania zwrotnego został zweryfikowany.
Najczęstsze pytania
- Czy mogę zapisywać w pamięci podręcznej klucz publiczny udostępniony przez serwer kluczy AdMob?
- Zalecamy zapisywanie w pamięci podręcznej klucza publicznego dostarczonego przez serwer AdMob w celu zmniejszenia liczby operacji wymaganych do weryfikacji wywołań zwrotnych SSV. Pamiętaj jednak, że klucze publiczne są regularnie rotowane i nie powinny być przechowywane w pamięci podręcznej dłużej niż 24 godziny.
- Jak często są publikowane klucze publiczne dostarczane przez serwer kluczy AdMob?
- Klucze publiczne dostarczane przez serwer kluczy AdMob są poddawane rotacji według harmonogramu. Aby weryfikacja wywołań zwrotnych usługi 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 mój serwer nie będzie dostępny?
- Google oczekuje
HTTP 200 OK
kodu stanu odpowiedzi w przypadku wywołań zwrotnych SSV. Jeśli serwer nie może nawiązać połączenia lub nie wyświetla oczekiwanej odpowiedzi, Google spróbuje ponownie wysłać wywołania SSV do pięciu razy w sekundach. - Jak sprawdzić, czy wywołania zwrotne SSV pochodzą od Google?
- Aby sprawdzić, czy wywołania SSV pochodzą z Google, użyj odwrotnego wyszukiwania DNS.