Lệnh gọi lại xác minh phía máy chủ là các yêu cầu URL, với tham số truy vấn do Google mở rộng, được Google gửi tới một hệ thống bên ngoài để thông báo rằng một người dùng cần được thưởng vì đã tương tác với một quảng cáo có tặng thưởng hoặc quảng cáo xen kẽ có tặng thưởng. Lệnh gọi lại SSV (xác minh phía máy chủ) dành cho quảng cáo có tặng thưởng cung cấp thêm một lớp bảo vệ giúp ngăn chặn tình trạng giả mạo lệnh gọi lại phía máy khách để trao thưởng cho người dùng.
Hướng dẫn này giúp bạn hiểu cách xác minh lệnh gọi lại SSV dành cho quảng cáo có tặng thưởng bằng cách sử dụng Ứng dụng Java của Tink (một thư viện mật mã bên thứ ba) để đảm bảo rằng tham số truy vấn trong lệnh gọi lại là giá trị hợp lệ. Mặc dù chúng tôi sử dụng Tink cho các mục đích của hướng dẫn này, nhưng bạn có thể sử dụng bất kỳ thư viện bên thứ ba nào có hỗ trợ ECDSA. Bạn cũng có thể kiểm tra máy chủ của mình bằng công cụ kiểm tra trong giao diện người dùng AdMob.
Điều kiện tiên quyết
- Bật tính năng xác minh phía máy chủ dành cho quảng cáo có tặng thưởng trên đơn vị quảng cáo của bạn.
Sử dụng RewardedAdsVerifier trong thư viện Ứng dụng Java của Tink
Kho lưu trữ Ứng dụng Java của Tink trên GitHub
bao gồm một
RewardedAdsVerifier
lớp trình trợ giúp nhằm rút gọn đoạn mã cần thiết để xác minh lệnh gọi lại SSV dành cho quảng cáo có tặng thưởng.
Việc sử dụng lớp này cho phép bạn xác minh URL gọi lại bằng đoạn mã sau.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
Nếu không phát sinh trường hợp ngoại lệ trong quá trình thực thi phương thức verify(), thì URL của lệnh gọi lại đã được xác minh thành công. Phần Trao thưởng cho người dùng
trình bày chi tiết các phương pháp hay nhất về thời điểm người dùng nên được trao thưởng. Để biết thông tin chi tiết về các bước mà lớp này sẽ thực hiện để xác minh lệnh gọi lại SSV dành cho quảng cáo có tặng thưởng,
bạn có thể tìm hiểu trong mục Tự xác minh SSV dành cho quảng cáo có tặng thưởng.
Các tham số gọi lại SSV
Lệnh gọi lại xác minh phía máy chủ chứa các tham số truy vấn mô tả hoạt động tương tác với quảng cáo có tặng thưởng. Tên tham số, nội dung mô tả và giá trị mẫu được liệt kê bên dưới. Các tham số được gửi theo thứ tự bảng chữ cái.
| Tên thông số | Mô tả | Giá trị mẫu |
|---|---|---|
| ad_network | Giá trị nhận dạng nguồn quảng cáo cho nguồn quảng cáo đã thực hiện quảng cáo này. Bạn có thể xem danh sách tên nguồn quảng cáo tương ứng với giá trị mã nhận dạng trong phần Giá trị nhận dạng nguồn quảng cáo. | 1953547073528090325 |
| ad_unit | Mã đơn vị quảng cáo AdMob được dùng để yêu cầu quảng cáo có tặng thưởng. | 2747237135 |
| custom_data | Chuỗi dữ liệu tuỳ chỉnh do
customData cung cấp.
Nếu ứng dụng không cung cấp chuỗi dữ liệu tuỳ chỉnh, thì giá trị tham số truy vấn này sẽ không có trong lệnh gọi lại SSV. |
SAMPLE_CUSTOM_DATA_STRING |
| key_id | Khóa được sử dụng để xác minh lệnh gọi lại SSV. Giá trị này liên kết đến khóa công khai do máy chủ khóa AdMob cung cấp. | 1234567890 |
| reward_amount | Số tiền thưởng như được chỉ định trong tùy chọn cài đặt đơn vị quảng cáo. | 5 |
| reward_item | Vật phẩm thưởng như được chỉ định trong tùy chọn cài đặt đơn vị quảng cáo. | coins |
| Chữ ký | Chữ ký cho lệnh gọi lại SSV do AdMob tạo ra. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
| timestamp | Dấu thời gian của thời điểm người dùng được trao thưởng dưới dạng thời gian Epoch tính bằng mili giây. | 1507770365237823 |
| transaction_id | Giá trị nhận dạng được mã hoá bằng hệ thập lục phân duy nhất cho từng sự kiện cấp phần thưởng do AdMob tạo. | 18fa792de1bca816048293fc71035638 |
| user_id | Giá trị nhận dạng người dùng do
userId cung cấp.
Nếu ứng dụng không cung cấp giá trị nhận dạng người dùng, thì tham số truy vấn này sẽ không có trong lệnh gọi lại SSV. |
1234567 |
Giá trị nhận dạng nguồn quảng cáo
Tên và giá trị nhận dạng nguồn quảng cáo
| Tên nguồn quảng cáo | Mã nguồn quảng cáo |
|---|---|
| Ad Generation (đặt giá thầu) | 1477265452970951479 |
| AdColony | 15586990674969969776 |
| AdColony (đặt giá thầu) | 6895345910719072481 |
| AdFalcon | 3528208921554210682 |
| Mạng AdMob | 5450213213286189855 |
| Thác nước trên Mạng AdMob | 1215381445328257950 |
| Applovin | 1063618907739174004 |
| Applovin (đặt giá thầu) | 1328079684332308356 |
| Chartboost | 2873236629771172317 |
| Chocolate Platform (đặt giá thầu) | 6432849193975106527 |
| Sự kiện tuỳ chỉnh | 18351550913290782395 |
| DT Exchange* * Trước ngày 21 tháng 9 năm 2022, mạng này được gọi là "Fyber Marketplace". | 2179455223494392917 |
| Equativ (đặt giá thầu)* * Trước ngày 12 tháng 1 năm 2023, mạng này được gọi là "Smart Adserver". | 5970199210771591442 |
| Fluct (đặt giá thầu) | 8419777862490735710 |
| Flurry | 3376427960656545613 |
| Fyber* * Nguồn quảng cáo này được dùng để báo cáo dữ liệu trong quá khứ. | 4839637394546996422 |
| i-mobile | 5208827440166355534 |
| Improve Digital (đặt giá thầu) | 159382223051638006 |
| Index Exchange (đặt giá thầu) | 4100650709078789802 |
| InMobi | 7681903010231960328 |
| InMobi (đặt giá thầu) | 6325663098072678541 |
| InMobi Exchange (đặt giá thầu) | 5264320421916134407 |
| IronSource | 6925240245545091930 |
| ironSource Ads (đặt giá thầu) | 1643326773739866623 |
| Leadbolt | 2899150749497968595 |
| Liftoff Monetize* * Trước ngày 30 tháng 1 năm 2023, mạng này được gọi là "Vungle". | 1953547073528090325 |
| Liftoff Monetize (đặt giá thầu)* * Trước ngày 30 tháng 1 năm 2023, mạng này được gọi là "Vungle (đặt giá thầu)". | 4692500501762622185 |
| LG U+AD | 18298738678491729107 |
| LINE Ads Network | 3025503711505004547 |
| Magnite DV+ (đặt giá thầu) | 3993193775968767067 |
| maio | 7505118203095108657 |
| maio (đặt giá thầu) | 1343336733822567166 |
| Media.net (đặt giá thầu) | 2127936450554446159 |
| Quảng cáo tự quảng bá đã dàn xếp | 6060308706800320801 |
| Meta Audience Network* * Trước ngày 6 tháng 6 năm 2022, mạng này được gọi là "Facebook Audience Network". | 10568273599589928883 |
| Meta Audience Network (đặt giá thầu)* * Trước ngày 6 tháng 6 năm 2022, mạng này được gọi là "Facebook Audience Network (đặt giá thầu)". | 11198165126854996598 |
| Mintegral | 1357746574408896200 |
| Mintegral (đặt giá thầu) | 6250601289653372374 |
| MobFox (đặt giá thầu) | 3086513548163922365 |
| MoPub (đã ngừng hoạt động) | 10872986198578383917 |
| myTarget | 8450873672465271579 |
| Nend | 9383070032774777750 |
| Nexxen (đặt giá thầu)* * Trước ngày 1 tháng 5 năm 2024, mạng này được gọi là "UnrulyX". | 2831998725945605450 |
| OneTag Exchange (đặt giá thầu) | 4873891452523427499 |
| OpenX (đặt giá thầu) | 4918705482605678398 |
| Pangle | 4069896914521993236 |
| Pangle (đặt giá thầu) | 3525379893916449117 |
| PubMatic (đặt giá thầu) | 3841544486172445473 |
| Chiến dịch đặt trước | 7068401028668408324 |
| SK planet | 734341340207269415 |
| Sharethrough (đặt giá thầu) | 5247944089976324188 |
| Smaato (đặt giá thầu) | 3362360112145450544 |
| Sonobi (đặt giá thầu) | 3270984106996027150 |
| Tapjoy | 7295217276740746030 |
| Tapjoy (đặt giá thầu) | 4692500501762622178 |
| Tencent GDT | 7007906637038700218 |
| TripleLift (đặt giá thầu) | 8332676245392738510 |
| Unity Ads | 4970775877303683148 |
| Unity Ads (đặt giá thầu) | 7069338991535737586 |
| Verve Group (đặt giá thầu) | 5013176581647059185 |
| Vpon | 1940957084538325905 |
| Yieldmo (đặt giá thầu) | 4193081836471107579 |
| YieldOne (đặt giá thầu) | 3154533971590234104 |
| Zucks | 5506531810221735863 |
Trao thưởng cho người dùng
Bạn cần cân bằng trải nghiệm người dùng và quy trình xác thực phần thưởng khi quyết định thời điểm trao thưởng cho người dùng. Lệnh gọi lại phía máy chủ có thể bị chậm trễ trước khi tiếp cận các hệ thống bên ngoài. Do đó, phương pháp hay nhất được đề xuất là sử dụng lệnh gọi lại phía máy khách để trao thưởng ngay cho người dùng, đồng thời xác thực tất cả phần thưởng khi nhận được lệnh gọi lại phía máy chủ. Phương pháp này mang lại trải nghiệm tốt cho người dùng, đồng thời đảm bảo tính hợp lệ của các phần thưởng được trao.
Tuy nhiên, đối với những ứng dụng mà trong đó tính hợp lệ của phần thưởng là điều rất quan trọng (ví dụ: phần thưởng ảnh hưởng đến hoạt động kinh tế trong trò chơi của ứng dụng) và tình trạng chậm trễ trong việc cấp phần thưởng có thể chấp nhận được, thì việc đợi lệnh gọi lại từ phía máy chủ được xác minh có thể là giải pháp tốt nhất.
Dữ liệu tuỳ chỉnh
Những ứng dụng cần có thêm dữ liệu trong lệnh gọi lại của cơ chế xác minh phía máy chủ nên sử dụng tính năng dữ liệu tuỳ chỉnh của quảng cáo có tặng thưởng. Bất kỳ giá trị chuỗi nào được đặt cho đối tượng quảng cáo có tặng thưởng đều sẽ được chuyển đến tham số truy vấn custom_data cho lệnh gọi lại của SSV. Nếu không có giá trị dữ liệu tuỳ chỉnh nào được đặt, thì giá trị tham số truy vấn custom_data sẽ không có trong lệnh gọi lại SSV.
Ví dụ sau đây đặt các tuỳ chọn SSV sau khi quảng cáo có tặng thưởng được tải:
Kotlin
RewardedAd.load(
AdRequest.Builder("AD_UNIT_ID").build(),
object : AdLoadCallback<RewardedAd> {
override fun onAdLoaded(ad: RewardedAd) {
// Rewarded ad loaded.
rewardedAd = ad;
rewardedAd.setServerSideVerificationOptions(
ServerSideVerificationOptions("userId", "customData")
)
}
override fun onAdFailedToLoad(adError: LoadAdError) {
// Rewarded ad failed to load.
rewardedAd = null
}
},
)
Java
RewardedAd.load(
new AdRequest.Builder("AD_UNIT_ID").build(),
new AdLoadCallback<RewardedAd>() {
@Override
public void onAdLoaded(@NonNull RewardedAd ad) {
// Rewarded ad loaded.
rewardedAd = ad;
rewardedAd.setServerSideVerificationOptions(
new ServerSideVerificationOptions("userId", "customData")
);
}
@Override
public void onAdFailedToLoad(@NonNull LoadAdError adError) {
// Rewarded ad failed to load.
rewardedAd = null;
}
}
);
Nếu muốn đặt chuỗi phần thưởng tuỳ chỉnh, bạn phải thực hiện việc này trước khi hiển thị quảng cáo.
Tự xác minh SSV dành cho quảng cáo có tặng thưởng
Bạn có thể xem các bước mà lớp RewardedAdsVerifier sẽ thực hiện để xác minh SSV có tặng thưởng bên dưới. Mặc dù đoạn mã được sử dụng nằm trong Java và
sử dụng thư viện Tink của bên thứ ba, nhưng bạn có thể triển khai các bước này theo ngôn ngữ mà mình muốn bằng cách sử dụng bất kỳ thư viện bên thứ ba nào có hỗ trợ
ECDSA.
Tìm nạp khoá công khai
Để xác minh lệnh gọi lại SSV dành cho quảng cáo có tặng thưởng, bạn cần có khóa công khai do AdMob cung cấp.
Bạn có thể tìm nạp danh sách khóa công khai mà hệ thống dùng để xác thực lệnh gọi lại SSV dành cho quảng cáo có tặng thưởng từ máy chủ khóa AdMob . Danh sách khóa công khai được cung cấp dưới dạng một biểu diễn JSON có định dạng tương tự như sau:
{
"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=="
},
],
}
Để truy xuất khóa công khai, hãy kết nối với máy chủ khóa AdMob và tải các khóa đó xuống. Mã sau đây giúp bạn hoàn thành công việc này và lưu phép biểu diễn JSON của các khóa đó vào biến 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();
}
Lưu ý: Các khóa công khai sẽ được thay đổi định kỳ. Chúng tôi sẽ gửi email cho bạn để thông báo về việc xoay vòng sắp tới. Nếu đang lưu khóa công khai vào bộ nhớ đệm, bạn nên cập nhật các khóa đó khi nhận được email này.
Sau khi tìm nạp, bạn phải phân tích cú pháp các khoá công khai. Phương thức parsePublicKeysJson bên dưới sẽ lấy chuỗi JSON (như ví dụ ở trên) làm thông tin đầu vào và tạo liên kết từ giá trị key_id đến khoá công khai. Các khoá này sẽ được đóng gói dưới dạng đối tượng ECPublicKey từ thư viện 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;
}
Lấy nội dung cần xác minh
2 tham số truy vấn cuối cùng của lệnh gọi lại SSV dành cho quảng cáo có tặng thưởng luôn có thứ tự là signature
và key_id,. Các tham số truy vấn còn lại chỉ định nội dung cần xác minh. Giả sử bạn đã định cấu hình AdMob để gửi lệnh gọi lại phần thưởng đến https://www.myserver.com/mypath. Đoạn mã sau đây là một ví dụ về lệnh gọi lại SSV dành cho quảng cáo có tặng thưởng, trong đó in đậm nội dung cần xác minh.
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
Mã dưới đây minh hoạ cách phân tích cú pháp nội dung cần được xác minh từ URL gọi lại dưới dạng mảng byte 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"));
Nhận chữ ký và key_id từ URL gọi lại
Sử dụng giá trị queryString từ bước trước, phân tích cú pháp tham số truy vấn signature và key_id của URL gọi lại như bên dưới:
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()));
Thực hiện việc xác minh
Bước cuối cùng là xác minh nội dung của URL gọi lại bằng khoá công khai thích hợp. Hãy lấy đường liên kết mà phương thức parsePublicKeysJson trả về và sử dụng thông số key_id của URL gọi lại để nhận khóa công khai từ đường liên kết đó. Sau đó, hãy xác minh chữ ký bằng cách sử dụng khóa công khai đó. Các bước này được minh hoạ bên dưới trong phương thức 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);
}
}
Nếu không phát sinh trường hợp ngoại lệ trong quá trình thực thi phương thức này, thì URL gọi lại đã được xác minh thành công.
Câu hỏi thường gặp
- Tôi có thể lưu khóa công khai do máy chủ khóa AdMob cung cấp vào bộ nhớ đệm không?
- Bạn nên lưu khóa công khai do máy chủ khóa AdMob cung cấp vào bộ nhớ đệm nhằm giảm số lượng thao tác mà bạn phải thực hiện để xác thực lệnh gọi lại SSV. Tuy nhiên, xin lưu ý rằng hệ thống sẽ thường xuyên xoay vòng các khóa công khai, do đó, bạn chỉ nên lưu các khóa công khai vào bộ nhớ đệm trong thời gian không quá 24 giờ.
- Tần suất xoay vòng của các khóa công khai do máy chủ khóa AdMob cung cấp như thế nào?
- Hệ thống sẽ xoay vòng các khóa công khai do máy chủ khóa AdMob cung cấp với lịch biểu không cố định. Để đảm bảo rằng quy trình xác minh lệnh gọi lại SSV tiếp tục hoạt động như dự kiến, bạn không nên lưu các khoá công khai vào bộ nhớ đệm trong thời gian quá 24 giờ.
- Điều gì sẽ xảy ra nếu tôi không thể truy cập vào máy chủ của mình?
- Google mong đợi mã phản hồi trạng thái thành công
HTTP 200 OKcho lệnh gọi lại SSV. Nếu bạn không thể truy cập vào máy chủ hoặc máy chủ không phản hồi như dự kiến, Google sẽ thử gửi lại các lệnh gọi lại SSV tối đa 5 lần trong khoảng thời gian một giây. - Làm cách nào để xác minh rằng lệnh gọi lại SSV là của Google?
- Bạn có thể sử dụng công cụ tra cứu DNS ngược để xác minh rằng các lệnh gọi lại SSV là của Google.