AdMob 獎勵視頻廣告服務端驗證

接入AdMob的獎勵視頻廣告服務端的驗證,這裏指的用戶觀看完廣告發獎勵的通知驗證。進入谷歌的文檔說明

文檔使用的google自己的庫Tink,有必要的可以從倉庫找到這個庫進行使用。

先說兩個字段,這兩個是在您的廣告那邊設置的,item就是你發獎勵的商品id

reward_amount 廣告單元設置中指定的獎勵金額。 5
reward_item 廣告單元設置中指定的獎品。 金幣

轉到你的廣告可以設置

 

這個就是你前端定義的用戶信息

custom_data 自定義數據字符串,其提供方法爲 setCustomData

如果應用未提供自定義數據字符串,此查詢參數值將不會出現在 SSV 回調中。

SAMPLE_CUSTOM_DATA_STRING

 

再前端添加自定義的用戶數據

轉到您的廣告設置服務端驗證地址,谷歌是以get的方式請求過來的,比如您的地址是https://xxx/ads/callback

 

下面進入驗證的流程,設置好了地址,當用戶觀看完廣告就會通知你的服務器地址了。谷歌是SHA256withECDSA的驗證方式。

1、獲取 AdMob公鑰

https://www.gstatic.com/admob/reward/verifier-keys.json

從這個地址獲取公鑰,公鑰列表以 JSON 表示形式提供,我們根據回調參數的key_id尋找對應的公鑰,注意這裏返回的公鑰是base64編碼過的,使用的時候需要進行解碼

/**
 * 獲取publicKey
 * @param keyId
 * @return
 */
public static String getVerifierKeys(final String keyId) {
	
//	{"keys":[{"keyId":3335741209,"pem":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+nzvoGqvDeB9+SzE6igTl7TyK4JB\nbglwir9oTcQta8NuG26ZpZFxt+F2NDk7asTE6/2Yc8i1ATcGIqtuS5hv0Q==\n-----END PUBLIC KEY-----","base64":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+nzvoGqvDeB9+SzE6igTl7TyK4JBbglwir9oTcQta8NuG26ZpZFxt+F2NDk7asTE6/2Yc8i1ATcGIqtuS5hv0Q=="}]}
	
	String publicKey=null;
	
	String result=XHttp.get("https://www.gstatic.com/admob/reward/verifier-keys.json");
	System.out.println("result:"+result);
	
	JSONObject json=new JSONObject(result);
	JSONArray jsonArray=json.getJSONArray("keys");
	for(int i=0;i<jsonArray.length();i++) {
		JSONObject jobj=jsonArray.getJSONObject(i);
		
		String key=jobj.optString("keyId");
		if(key.equalsIgnoreCase(keyId)) {
			publicKey=jobj.getString("base64");
		}
	}
	
	return publicKey;
}

返回的數據格式如下:

{
     "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=="
        },
      ],
    }
    

 

2、獲取要驗證的內容

public static Map<String,Object> getDataToVerify() {
	String rewardUrl="http://xxx/ads/callback?ad_network=5450213213286189855&ad_unit=4826801875&custom_data=375759667%2C1%2CroleId&reward_amount=1&reward_item=Rewards&timestamp=1590396116896&transaction_id=16855da7c17a63500096b5acca880b9d&signature=MEQCIAvEJKvCRd_7QLKEq6-BvsurUKpppJkQDFzBUe1ZqvO0AiBFRFEJAWAo0Qmaw2FbPDuC62cJD6XhMEPIfiyLkxK4ug&key_id=3335741209";

	Map<String,Object> map=new HashMap<String, Object>();
	
	System.out.println("rewardUrl:"+rewardUrl);
	String SIGNATURE_PARAM_NAME = "signature=";
   
    URI uri = null;
    try {
      uri = new URI(rewardUrl);
    } catch (Exception ex) {
      ex.printStackTrace();
      System.out.println("===11===");
    }
    String queryString = uri.getQuery();
    int i = queryString.indexOf(SIGNATURE_PARAM_NAME);
    if (i == -1) {
//      throw new Exception("needs a signature query parameter");
    	System.out.println("===22===");
    }
    
    String ystr=queryString
            .substring(0, i - 1);
    System.out.println("yanz:"+ ystr);
    
    byte[] queryParamContentData =
    		ystr
            // i - 1 instead of i because of & in the query string
            .getBytes(Charset.forName("UTF-8"));
    
    
    
    String KEY_ID_PARAM_NAME = "key_id=";

    String sigAndKeyId = queryString.substring(i);
    i = sigAndKeyId.indexOf(KEY_ID_PARAM_NAME);
    if (i == -1) {
    	System.out.println("needs a key_id query parameter");
    }
    String sig =
        sigAndKeyId.substring(
            SIGNATURE_PARAM_NAME.length(), i - 1 /* i - 1 instead of i because of & */);
    String keyId = sigAndKeyId.substring(i + KEY_ID_PARAM_NAME.length());
    
    System.out.println("sig:"+sig);
    System.out.println("keyId:"+keyId);
    
	map.put("queryParamContentData", queryParamContentData);
	map.put("keyId", keyId);
	
	 try {
		map.put("sig",org.apache.commons.codec.binary.Base64.decodeBase64(sig.getBytes("utf-8")) );
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
//	map.put("sig", Base64.urlSafeDecode(sig));
    
    return map;

}

rewardUrl就是您的回調地址和谷歌請求過來的參數,獲取驗證的內容queryParamContentData、keyId、sig

java獲取get請求參數和url的方式

StringBuffer url=request.getRequestURL();
url.append("?").append(request.getQueryString());

3、進行驗證

/**
 * 驗證
 * @param data 需要驗證的數據
 * @param _key  public key
 * @param sig 谷歌返回的signature參數
 * @return
 */
public static boolean verifySign(byte[] data, byte[] _key, byte[] sig) {

    try {
        java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(
                _key);
        KeyFactory keyf = KeyFactory.getInstance("EC"); 
        PublicKey publicKey = keyf.generatePublic(bobPubKeySpec);

        Signature signer = Signature.getInstance("SHA256withECDSA");
        signer.initVerify(publicKey);
        signer.update(data);
        return (signer.verify(sig));
    }
    catch(Exception ex)
    {
        System.out.println(ex.getMessage());
        return false;
    }
}

 

 Map<String,Object> map=getDataToVerify();
//	ecdsaVerifyJce.verify((byte[])map.get("sig"), (byte[])map.get("queryParamContentData"));
    
    String publicKey=getVerifierKeys((String)map.get("keyId"));
    
    boolean isverfy=verifySign((byte[])map.get("queryParamContentData"), org.apache.commons.codec.binary.Base64.decodeBase64(publicKey),(byte[]) map.get("sig"));
    System.out.println("isverfy:"+isverfy);

 

運行不發生異常,且返回true就是驗證通過了。

注意:獲取的公鑰base64的值需要進行base64解碼,回調過來的參數signature字段也是需要進行base64解碼

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章