Lệnh gọi lại xác minh phía máy chủ là các yêu cầu URL kèm theo 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 người dùng sẽ được tặng thưởng khi tương tác với 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 SSO có tặng thưởng (xác minh phía máy chủ) cung cấp một lớp bảo vệ bổ sung chống lại việc giả mạo các lệnh gọi lại phía máy khách để tặng thưởng cho người dùng.
Hướng dẫn này cho bạn biết cách xác minh lệnh gọi lại CSE có tặng thưởng bằng cách sử dụng Ứng dụng Java của Tink của bên thứ ba để đảm bảo rằng các tham số truy vấn trong lệnh gọi lại các giá trị hợp lệ. Mặc dù Tink được sử dụng cho các mục đích của hướng dẫn này, nhưng bạn có thể chọn sử dụng bất kỳ thư viện bên thứ ba nào hỗ trợ ECDSA. Bạn cũng có thể kiểm tra máy chủ bằng quy trình kiểm thử trong giao diện người dùng AdMob.
Hãy xem giải pháp này có hiệu quả hoàn toàn ví dụ bằng cách sử dụng spring-boot của Java.
Điều kiện tiên quyết
Tích hợp quảng cáo có tặng thưởng vào ứng dụng di động với Trình bổ trợ Unity quảng cáo trên thiết bị di động của Google phiên bản 3.12.0 trở lên.
Bật có tặng thưởng phía máy chủ xác minh trên đơn vị quảng cáo của mình.
Sử dụng AGDKsVerifier 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
RewardedAdsVerifier
để rút gọn mã cần thiết nhằm xác minh lệnh gọi lại AFS có tặng thưởng.
Khi sử dụng lớp này, bạn có thể xác minh URL gọi lại bằng mã sau.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
Nếu phương thức verify()
thực thi mà không phát sinh trường hợp ngoại lệ, thì lệnh gọi lại
URL đã được xác minh thành công. Phần Tặng thưởng cho người dùng
thông tin chi tiết về các phương pháp hay nhất về thời điểm người dùng sẽ được tặng thưởng. Đối với
bảng 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 CSE có tặng thưởng,
bạn có thể đọc qua bài viết Xác minh thủ công quảng cáo có tặng thưởng
Xin nhắc lại.
Các tham số lệnh gọi lại TCF
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ả lượt tương tác với quảng cáo có tặng thưởng. Tên thông số, nội dung mô tả và giá trị mẫu là được liệt kê bên dưới. Hệ thống sẽ gửi các thông số 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 của nguồn quảng cáo đã thực hiện quảng cáo này. Nguồn quảng cáo tên tương ứng với giá trị ID được liệt kê trong phần Quảng cáo giá trị nhận dạng nguồn. | 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 |
key_id | Khoá được dùng để xác minh lệnh gọi lại SSO. Giá trị này liên kết với một khoá công khai do máy chủ khoá AdMob cung cấp. | 1234567890 |
reward_amount | Số tiền thưởng như được chỉ định trong chế độ cài đặt đơn vị quảng cáo. | 5 |
reward_item | Vật phẩm thưởng như được chỉ định trong chế độ cài đặt đơn vị quảng cáo. | xu |
Chữ ký | Chữ ký cho lệnh gọi lại CPF do AdMob tạo. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
dấu thời gian | Dấu thời gian về thời điểm người dùng được tặng thưởng dưới dạng Epoch time tính bằng mili giây. | 1507770365237823 |
transaction_id | Giá trị nhận dạng được mã hoá hex duy nhất cho từng sự kiện cấp phần thưởng do AdMob tạo ra. | 18fa792de1bca816048293fc71035638 |
user_id | Giá trị nhận dạng người dùng do
SetUserId .
Nếu ứng dụng không cung cấp giá trị nhận dạng người dùng, tham số truy vấn này sẽ không hiển thị trong lệnh gọi lại TCF. |
1234567 |
Giá trị nhận dạng nguồn quảng cáo
Tên và mã nguồn quảng cáo
广告来源名称 | 广告来源 ID |
---|---|
Aarki(出价) | 5240798063227064260 |
Ad Generation(出价) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony(非 SDK)(出价) | 4600416542059544716 |
AdColony(出价) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
AdMob 广告联盟 | 5450213213286189855 |
AdMob 广告联盟广告瀑布流 | 1215381445328257950 |
ADResult | 10593873382626181482 |
AMoAd | 17253994435944008978 |
AppLovin | 1063618907739174004 |
AppLovin(出价) | 1328079684332308356 |
Chartboost | 2873236629771172317 |
Chocolate Platform(出价) | 6432849193975106527 |
跨渠道 (MdotM) | 9372067028804390441 |
自定义事件 | 18351550913290782395 |
DT Exchange* * 在 2022 年 9 月 21 日之前,该广告联盟称为“Fyber Marketplace”。 | 2179455223494392917 |
EMX(出价) | 8497809869790333482 |
Fluct(出价) | 8419777862490735710 |
小风 | 3376427960656545613 |
Fyber* * 此广告来源用于生成历史报告。 | 4839637394546996422 |
i-mobile | 5208827440166355534 |
优化数字化(出价) | 159382223051638006 |
Index Exchange(出价) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi(出价) | 6325663098072678541 |
InMobi Exchange(出价) | 5264320421916134407 |
IronSource | 6925240245545091930 |
ironSource Ads(出价) | 1643326773739866623 |
Leadbolt | 2899150749497968595 |
LG U+AD | 18298738678491729107 |
LINE 广告联盟 | 3025503711505004547 |
maio | 7505118203095108657 |
maio(出价) | 1343336733822567166 |
Media.net(出价) | 2127936450554446159 |
参与中介的自家广告 | 6060308706800320801 |
Meta Audience Network* * 在 2022 年 6 月 6 日之前,该广告联盟称为“Facebook Audience Network”。 | 10568273599589928883 |
Meta Audience Network(出价)* * 在 2022 年 6 月 6 日之前,该广告联盟称为“Facebook Audience Network(出价)”。 | 11198165126854996598 |
Mintegral | 1357746574408896200 |
Mintegral(出价) | 6250601289653372374 |
MobFox | 8079529624516381459 |
MobFox(出价) | 3086513548163922365 |
MoPub(已弃用) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
Nexxen(出价)* * 在 2024 年 5 月 1 日之前,该广告联盟称为“UnrulyX”。 | 2831998725945605450 |
ONE by AOL (Millennial Media) | 6101072188699264581 |
ONE by AOL (Nexage) | 3224789793037044399 |
OneTag Exchange(出价) | 4873891452523427499 |
OpenX(出价) | 4918705482605678398 |
邦格尔 | 4069896914521993236 |
Pangle(出价) | 3525379893916449117 |
PubMatic(出价) | 3841544486172445473 |
预订型广告系列 | 7068401028668408324 |
RhythmOne(出价) | 2831998725945605450 |
Rubicon(出价) | 3993193775968767067 |
SK 星球 | 734341340207269415 |
Sharethrough(出价) | 5247944089976324188 |
Smaato(出价) | 3362360112145450544 |
Equativ(出价)* * 在 2023 年 1 月 12 日之前,该广告联盟称为“Smart Adserver”。 | 5970199210771591442 |
Sonobi(出价) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy(出价) | 4692500501762622178 |
Tencent GDT | 7007906637038700218 |
TripleLift(出价) | 8332676245392738510 |
Unity 广告 | 4970775877303683148 |
Unity Ads(出价) | 7069338991535737586 |
Verizon Media | 7360851262951344112 |
Verve Group(出价) | 5013176581647059185 |
Vpon | 1940957084538325905 |
Liftoff Monetize* * 在 2023 年 1 月 30 日之前,该广告联盟称为“Vungle”。 | 1953547073528090325 |
Liftoff Monetize(出价)* * 在 2023 年 1 月 30 日之前,该广告联盟称为“Vungle(出价)”。 | 4692500501762622185 |
Yieldmo(出价) | 4193081836471107579 |
YieldOne(出价) | 3154533971590234104 |
Zucks | 5506531810221735863 |
Tặng thưởng cho người dùng
Điều quan trọng là phải cân bằng trải nghiệm người dùng và xác thực phần thưởng khi quyết định thời điểm tặng thưởng cho người dùng. Các 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 để tặng thưởng cho người dùng ngay lập tức, trong khi vẫn thực hiện xác thực tất cả các phần thưởng khi nhận được lệnh gọi lại phía máy chủ. Chiến dịch này phương pháp tiếp cận này mang lại trải nghiệm tốt cho người dùng trong khi vẫn đảm bảo tính hợp lệ của phần thưởng.
Tuy nhiên, đối với các ứng dụng yêu cầu tính hợp lệ của phần thưởng là rất quan trọng (ví dụ: phần thưởng sẽ ảnh hưởng đến hoạt động kinh tế của ứng dụng trong trò chơi) đồng thời việc trao phần thưởng bị chậm trễ chấp nhận được, chờ lệnh gọi lại phía máy chủ được xác minh có thể là tốt nhất phương pháp tiếp cận.
Dữ liệu tùy chỉnh
Những ứng dụng cần có thêm dữ liệu trong lệnh gọi lại 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 quảng cáo có tặng thưởng
được truyền đến tham số truy vấn custom_data
của lệnh gọi lại adb. Nếu không
sau khi đã đặt giá trị dữ liệu tùy chỉnh, thì giá trị tham số truy vấn custom_data
sẽ không là
hiển thị trong lệnh gọi lại TCF.
Mã mẫu sau đây minh hoạ cách đặt các tuỳ chọn của tính năng SSO sau đã tải quảng cáo có tặng thưởng.
private void LoadRewardedAd(string adUnitId)
{
// Send the request to load the ad.
AdRequest adRequest = new AdRequest();
RewardedAd.Load(adUnitId, adRequest, (RewardedAd rewardedAd, LoadAdError error) =>
{
// If the operation failed with a reason.
if (error != null)
{
Debug.LogError("Rewarded ad failed to load an ad with error : " + error);
return;
}
var options = new ServerSideVerificationOptions
.Builder()
.SetCustomData("SAMPLE_CUSTOM_DATA_STRING")
.Build()
rewardedAd.SetServerSideVerificationOptions(options);
});
}
Nếu muốn đặt chuỗi phần thưởng tuỳ chỉnh, bạn phải thực hiện trước khi hiển thị quảng cáo.
Quy trình xác minh AFS có tặng thưởng theo cách thủ công
Các bước mà lớp RewardedAdsVerifier
sẽ thực hiện để xác minh một phần thưởng có tặng thưởng
Dưới đây là sơ lược về tính năng Quy trình đăng ký xác thực (SSV) Mặc dù các đoạn mã được bao gồm nằm trong Java và
tận dụng thư viện bên thứ ba của Tink. Bạn có thể triển khai các bước này trong
ngôn ngữ bạn chọn, sử dụng bất kỳ thư viện bên thứ ba nào hỗ trợ
ECDSA.
Tìm nạp khoá công khai
Để xác minh lệnh gọi lại SAML có tặng thưởng, bạn cần có khoá công khai do AdMob cung cấp.
Bạn có thể sử dụng danh sách các khoá công khai được dùng để xác thực lệnh gọi lại SAML có tặng thưởng được tìm nạp từ khoá AdMob máy chủ. Danh sách khoá công khai được cung cấp dưới dạng giá trị 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 khoá công khai, hãy kết nối với máy chủ khoá AdMob rồi tải
khoá. Mã sau đây giúp hoàn thành công việc này và lưu JSON
biểu diễn các khoá cho 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();
}
Xin lưu ý rằng chúng tôi sẽ thường xuyên xoay vòng các khoá công khai. Bạn sẽ nhận được email để thông báo cho bạn về vòng xoay sắp tới. Nếu đang lưu khoá công khai vào bộ nhớ đệm, bạn nên cập nhật các khoá 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. Chiến lược phát hành đĩa đơn
Phương thức parsePublicKeysJson
bên dưới sẽ lấy một chuỗi JSON, chẳng hạn như ví dụ
ở trên làm dữ liệu đầu vào và tạo một mối liên kết từ giá trị key_id
đến khoá công khai,
được đóng gói dưới dạng đối tượng ECPublicKey
trong 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 được xác minh
Hai thông số truy vấn cuối cùng của lệnh gọi lại AFS có tặng thưởng luôn là signature
và key_id,
theo thứ tự đó. Các tham số truy vấn còn lại chỉ định nội dung
cần được 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ã dưới đây cho thấy một ví dụ về quảng cáo có tặng thưởng
Lệnh gọi lại CPF, trong đó nội dung cần xác minh được làm nổi bật.
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"));
Lấy 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 signature
và
Tham số truy vấn key_id
từ URL gọi lại như minh hoạ dưới đây:
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()));
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. Lấy bản đồ được trả về từ
Phương thức parsePublicKeysJson
và sử dụng tham số key_id
từ lệnh gọi lại
URL để nhận khoá công khai qua mối liên kết đó. Sau đó, hãy xác minh chữ ký bằng
khoá công khai đó. Bạn có thể xem các bước này ở 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 phương thức này thực thi mà không phát sinh trường hợp ngoại lệ, thì URL gọi lại sẽ là đã xác minh thành công.
Câu hỏi thường gặp
- Tôi có thể lưu khoá công khai do máy chủ khoá AdMob cung cấp vào bộ nhớ đệm không?
- Bạn nên lưu khóa công khai do khóa AdMob cung cấp vào bộ nhớ đệm máy chủ để giảm số lượng thao tác cần thực hiện nhằm xác thực tính năng SSO lệnh gọi lại. Tuy nhiên, xin lưu ý rằng chúng tôi thường xuyên xoay vòng các khoá công khai nên bạn không nên được lưu vào bộ nhớ đệm lâu hơn 24 giờ.
- Tần suất xoay vòng các khoá công khai do máy chủ khoá AdMob cung cấp là bao nhiêu?
- Các khoá công khai do máy chủ khoá AdMob cung cấp được xoay vòng trên một biến . Để đảm bảo rằng quy trình xác minh lệnh gọi lại SSO tiếp tục hoạt động thì khoá công khai không nên được lưu vào bộ nhớ đệm quá 24 giờ.
- Điều gì xảy ra nếu tôi không thể truy cập vào máy chủ?
- Google dự kiến sử dụng mã phản hồi trạng thái thành công
HTTP 200 OK
cho Quy trình tích hợp lệnh gọi lại. Nếu không thể truy cập vào máy chủ của bạn hoặc máy chủ không cung cấp Google sẽ cố gắng gửi lại lệnh gọi lại SSO tối đa 5 lần khoảng thời gian một giây. - Làm cách nào để xác minh rằng các lệnh gọi lại của Google đều đến từ 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 của hệ thống SSO là của Google.