日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

Android應用集成SDK

您需要在應用中集成SDK,才能在控制臺BOT管理中配置App防爬場景化規則。本文介紹了如何為Android應用集成WAF App防護SDK(以下簡稱SDK)。

背景信息

App防護SDK主要用于對通過App客戶端發起的請求進行簽名。WAF服務端通過校驗App請求簽名,識別App業務中的風險、攔截惡意請求,實現App防護的目的。

關于App防護提供的SDK所涉及的隱私政策,請參見Web應用防火墻App防護SDK隱私政策。

使用限制

  • Android應用支持如下三個軟件版本的SO:arm64-v8a、armeabi-v7a。

  • Android應用的API版本必須是16及以上。

  • init初始化接口存在耗時操作,調用后不能立即同步調用vmpSign接口,請確保SDK的初始化接口和簽名接口調用時間間隔2秒以上。

  • 當使用proguard進行代碼混淆時,請使用-keep選項對SDK的接口函數進行設置,例如:

    -keep class com.aliyun.TigerTally.** {*;}

前提條件

  • 已獲取Android應用對應的SDK。

    獲取方法:請提交工單,聯系產品技術專家獲取SDK。

    說明

    Android應用對應的SDK包含1個AAR文件,文件名為AliTigerTally_X.Y.Z.aar,其中X.Y.Z表示版本號。

  • 已獲取SDK認證密鑰(即appkey)。

    開啟BOT管理后,即可在新建或編輯防護模板的防護場景定義配置導向中的APP SDK集成單擊獲取并復制appkey,獲取SDK認證密鑰。該密鑰用于發起SDK初始化請求,需要在集成代碼中使用。image

    說明

    每個阿里云賬號擁有唯一的appkey(適用于所有接入WAF防護的域名),且Android和iOS應用集成SDK時都使用該appkey。

    認證密鑰示例:****OpKLvM6zliu6KopyHIhmneb_****u4ekci2W8i6F9vrgpEezqAzEzj2ANrVUhvAXMwYzgY_****vc51aEQlRovkRoUhRlVsf4IzO9dZp6nN_****Wz8pk2TDLuMo4pVIQvGaxH3vrsnSQiK****。

步驟一:新建工程

以Android Studio工具為例,新建一個Android工程,并按照配置向導完成創建。創建好的工程目錄如下圖所示。tigertally-demo-spk

步驟二:集成AAR包

  1. 將獲取到的SDK文件AliTigerTally_X.Y.Z.aar拖放到/project/app/libs目錄中。拷貝AAR文件

  2. 打開App的build.gradle文件,將libs目錄添加為查找依賴的源,并添加編譯依賴為AliTigerTally_X.Y.Z.aar。

  3. 具體配置信息如下所示:

    重要

    您需要將AliTigerTally_X.Y.Z.aar文件的版本號X.Y.Z替換成您獲取的AAR文件的版本號。

    //...
    
    repositories {
        flatDir {
           dirs 'libs'
       }
    }
    
    dependencies {
        // ...
        compile(name: 'AliTigerTally_X.Y.Z', ext: 'aar')
    }

步驟三:過濾SO CPU架構

如果項目在此之前未使用過SO,需在build.gradle中添加以下配置。

android {
    defaultConfig {
        ndk {
            abiFilters 'arm64-v8a', 'armeabi-v7a'
        }
    }
}

步驟四:為應用申請權限

  • 必備權限

    <uses-permission android:name="android.permission.INTERNET"/>
  • 可選權限

    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    說明

    android.permission.READ_EXTERNAL_STORAGE和android.permission.WRITE_EXTERNAL_STORAGE權限在Android 6.0及以上版本需要動態申請。

步驟五:添加集成代碼

  1. 數據簽名。

    1. 設置業務自定義的終端用戶標識,方便您更靈活地配置WAF防護策略。

      /**
      * 設置用戶賬戶
      *
      * @param account 賬戶
      * @return 錯誤碼
      */
      public static int setAccount(String account)
      • 參數說明

        • account:String類型,表示標識一個用戶的字符串,建議您使用脫敏后的格式.

      • 返回值:int類型,返回是否設置成功,0表示成功,-1表示失敗。

      • 示例代碼

        // 游客身份可以暫時先不setAccount,直接初始化;登錄以后調用setAccount和重新初始化
        String account = "user001";
        TigerTallyAPI.setAccount(account);
    2. 初始化SDK,執行一次初始化采集。

      一次初始化采集表示采集一次終端設備信息,您可以根據業務的不同,重新調用init函數進行初始化采集。

      初始化采集分為兩種模式:采集全量數據、采集除需授權字段外的數據(不采集涉及終端設備用戶隱私的字段,包括:imei、imsi、simSerial、wifiMac、wifiList、bluetoothMac、androidId)。

      說明

      建議您在終端用戶同意App的隱私政策前,采集除需授權字段外的數據;在終端用戶同意App的隱私政策后,再采集全量數據。采集全量數據有利于更好地識別風險。

      // 采集類型: 全量采集, 不采集隱私數據
      public enum CollectType { DEFAULT, NOT_GRANTED }
      
      // 初始化回調
      public interface TTInitListener {
          // code表示接口調用狀態碼
          void onInitFinish(int code);
      }
      
      /**
       * SDK 初始化,帶 callback
       *
       * @param appkey 密鑰
       * @param type 采集數據的類型
       * @param otherOptions 各類參數選項
       * @return 錯誤碼
       */
      public static int init(Context context, String appkey, CollectType type,
                             Map<String, String> otherOptions, TTInitListener listener);
      • 參數說明

        • context:Context類型,傳入您應用的上下文。

        • appkey:String類型,設置為您的SDK認證密鑰。

        • type:CollectType類型,設置采集模式。取值:

          • DEFAULT:表示采集全量數據。

          • NO_GRANTED:表示采集除需授權字段外的數據。

        • otherOptions:Map<String, String>類型,信息采集可選項,默認可以為null。可選參數如下

          字段名

          說明

          示例

          IPv6

          是否使用IPv6域名上報設備信息。

          • 0:使用IPv4域名,默認值

          • 1:使用IPv6域名。

          1

          Intl

          是否使用國際域名上報設備信息。

          • 0:國內上報,默認值

          • 1:國際上報。

          1

        • listener:TTInitListener類型,SDK初始化回調接口,可在回調中判斷初始化結果的具體狀態,默認可以傳null。

          TTCode

          Code

          備注

          TT_SUCCESS

          0

          SDK初始化成功

          TT_NOT_INIT

          -1

          SDK未調用初始化

          TT_NOT_PERMISSION

          -2

          SDK需要的Android基礎權限未完全授權

          TT_UNKNOWN_ERROR

          -3

          系統未知錯誤

          TT_NETWORK_ERROR

          -4

          網絡錯誤

          TT_NETWORK_ERROR_EMPTY

          -5

          網絡錯誤,返回內容為空串

          TT_NETWORK_ERROR_INVALID

          -6

          網絡返回的格式非法

          TT_PARSE_SRV_CFG_ERROR

          -7

          服務端配置解析失敗

          TT_NETWORK_RET_CODE_ERROR

          -8

          網關返回失敗

          TT_APPKEY_EMPTY

          -9

          AppKey為空

          TT_PARAMS_ERROR

          -10

          其他參數錯誤

          TT_FGKEY_ERROR

          -11

          密鑰計算錯誤

          TT_APPKEY_ERROR

          -12

          SDK版本和AppKey版本不匹配

      • 返回值:int類型,返回初始化結果,0表示成功,-1表示失敗。

      • 示例代碼

        // appkey代表阿里云客戶平臺分配的認證密鑰
        final String appkey="******";
        // 可選參數, 可配置IPv6與國際上報
        Map<String, String> options = new HashMap<>();
        options.put("IPv6", "0");// 配置為IPv4
        options.put("Intl", "0");// 配置為國內上報
        
        // 一次初始化采集,代表一次設備信息采集,可以根據業務的不同,重新調用函數init初始化采集
        // 全量采集
        int ret = TigerTallyAPI.init(this.getApplicationContext(), appkey, TigerTallyAPI.CollectType.DEFAULT, options, null);
        
        // 不采集隱私字段
        int ret = TigerTallyAPI.init(this.getApplicationContext(), appkey, TigerTallyAPI.CollectType.NOT_GRANTED, options, null);
        Log.d("AliSDK", "ret:" + ret);

    3. 數據簽名。

      使用vmp技術對輸入數據input進行簽名處理,并且返回wtoken字符串用于請求認證。

      /**
       * 數據簽名
       *
       * @param type 簽名類型
       * @param input 簽名數據
       * @return wtoken
       */
      public static String vmpSign(int type, byte[] input);
      • 參數說明

        • type:CollectType類型,設置數據簽名類型,固定取值1。

        • input:byte[]類型,表示待簽名的數據,一般是整個請求體request body。

      • 返回值:String類型,返回wtoken字符串。

      • 示例代碼

        // 默認簽名
        String body = "i am the request body, encrypted or not!";
        String wtoken = TigerTallyAPI.vmpSign(1, body.getBytes("UTF-8"));
        Log.d("AliSDK", "wToken:" + wtoken);
    4. 數據哈希。

      自定義加簽使用接口,將對傳入的數據計算生成一個whash字符串,Post、Put、Patch請求需要傳入request body,Get、Delete請求傳入完整的URL地址。同時,whash字符串需要添加到http請求header的ali_sign_whash中。

      // 請求類型:
      public enum RequestType { GET, POST, PUT, PATCH, DELETE }
      
      /**
       *  自定義Hash簽名數據 
       *
       * @param type  數據類型
       * @param input 哈希數據
       * @return whash
       */
      public static String vmpHash(RequestType type, byte[] input);
      • 參數說明

        • type:RequestType類型,設置數據類型。取值:

          • GET:表示Get請求數據。

          • POST:表示Post請求數據。

          • PUT:表示Put請求數據。

          • PATCH:表示Patch請求數據。

          • DELETE:表示Delete請求數據。

        • input:byte[]類型,表示待加簽的數據。

      • 返回值:String類型,返回whash字符串。

      • 示例代碼

        // get 請求
        String url = "https://tigertally.aliyun.com/apptest";
        String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.GET, url.getBytes());
        String wtoken = TigerTallyAPI.vmpSign(1, whash.getBytes());
        Log.d("AliSDK", "whash:" + whash + ", wtoken:" + wtoken);
        
        // post 請求
        String body = "hello world";
        String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.POST, body.getBytes());
        String wtoken = TigerTallyAPI.vmpSign(1, whash.getBytes());
        Log.d("AliSDK", "whash:" + whash + ", wtoken:" + wtoken);
        說明
        • 調用vmpHash進行自定義加簽時,簽名接口vmpSign的參數input為生成的whash字符串,且在配置App防爬場景化策略時,自定義加簽字段的值需設置為ali_sign_whash。

        • 調用vmpHash生成Get請求的whash時,必須保證輸入的URL地址和最終網絡請求的URL一致,特別需要注意UrlEncode情況,部分框架會自動對中文或者參數進行UrlEncode編碼。

        • 接口vmpHash的參數input不支持字節或者空字符串,輸入為URL時必須存在Path或者Param。

        • 調用vmpSign時,如果請求體為空,例如,Post請求或Get請求的body為空,則填寫空對象null或空字符串的Bytes值,例如"".getBytes("UTF-8")。

        • 當whash或wtoken為以下字符串時表示初始化流程存在異常:

          • you must call init first:表示未調用init函數。

          • you must input correct data:表示傳入數據錯誤。

          • you must input correct type:表示傳入類型錯誤。

  2. 二次校驗

    1. 判斷結果。

      根據response中cookie和body字段判斷是否要進行二次校驗。header中可能存在多個Set-Cookie。

      /**
       * 判斷是否進行二次校驗
       *
       * @param cookie cookie
       * @param body body
       * @return 0:通過 1:二次校驗
       */
      public static int cptCheck(String cookie, String body)
      • 參數說明

        • cookie:String類型,設置請求response中全部cookie。

        • body:String類型,設置請求response中全部body。

      • 返回值:int類型,返回決策結果,0表示通過,1表示需要二次校驗。

      • 示例代碼

        String cookie = "key1=value1;kye2=value2;";
        String body = "....";
        int recheck = TigerTallyAPI.cptCheck(cookie, body);
        Log.d("AliSDK", "recheck:" + recheck);
    2. 創建滑塊。

      根據cptCheck返回結果決定是否要創建一個滑塊對象,TTCaptcha對象提供show和dismiss方法,對應顯示滑塊和隱藏滑塊窗口。TTOption封裝了滑塊可配置的參數,TTListener包含了滑塊的三種回調狀態。如果需要自定義滑塊窗口頁面需要傳入自定義頁面地址,支持本地 html文件,或者遠程頁面。

      /**
       * 創建滑塊對象
       *
       * @param activity 顯示頁面
       * @param option 參數
       * @param listener 回調
       * @return 滑塊驗證對象
       */
      public static TTCaptcha cptCreate(Activity activity, TTOption option, TTListener listener);
      
      
      /**
       * 滑塊對象
       */
      public class TTCaptcha {
          /**
           * 顯示滑塊
           */
          public void show();
      
          /**
           * 隱藏滑塊
           */
          public void dismiss();
      
          /**
           * 獲取滑塊traceId,用于數據統計
           */
          public String getTraceId();
      }
      
      /**
       * 滑塊參數
       */
      public static class TTOption {
          // 是否支持點擊空白處隱藏滑塊
          public boolean cancelable;
      
          // 是否支持隱藏滑塊錯誤碼
          public boolean hideError;
      
          // 自定義頁面,支持本地html文件和遠程url
          public String customUri;
      
          // 設置語言
          public String language;
      
          // 二次校驗請求traceId
          public String traceId;
      
          // 滑塊標題文案,最長20個字符
          public String titleText;
      
          // 滑塊描述文案,最長60個字符
          public String descText;
      
          // 滑塊顏色,格式例如"#007FFF"
          public String slideColor;
      
          // 是否隱藏traceId
          public boolean hideTraceId;
      }
      
      /**
       * 滑塊回調
       */
      public interface TTListener {
          /**
           * 驗證成功
           *
           * @param captcha 滑塊對象
           * @param data token, 默認為traceId
           */
          void success(TTCaptcha captcha, String data);
      
          /**
           * 驗證失敗
           *
           * @param captcha 滑塊對象
           * @param code 錯誤碼
           */
          void failed(TTCaptcha captcha, String code);
      
          /**
           * 驗證異常
           *
           * @param captcha 滑塊對象
           * @param code 錯誤碼
           * @param message 錯誤信息
           */
          void error(TTCaptcha captcha, int code, String message);
      }
      • 參數說明

        • activity:Activity類型,設置當前頁面activity。

        • option:TTOption類型,設置滑塊配置參數。

        • listener:TTlistener類型,設置滑塊狀態回調。

      • 返回值:TTCaptcha類型,返回滑塊對象。

      • 示例代碼

        TTCaptcha.TTOption option = new TTCaptcha.TTOption();
        // option.customUri  = "file:///android_asset/ali-tt-captcha-demo.html";
        // option.traceId    = "4534534534adf433534534543";
        option.titleText  = "測試 Title";
        option.descText   = "測試 Description";
        option.language   = "cn";
        option.cancelable = true;
        option.hideError  = true;
        option.slideColor = "#007FFF";
        option.hideTraceId= true;
        
        TTCaptcha captcha = TigerTallyAPI.cptBuild(this, option, new TTCaptcha.TTListener() {
            @Override
            public void success(TTCaptcha captcha, String data) {
                Log.d(TAG, "captcha check success:" + data);
                captcha.dismiss();
            }
            @Override
            public void failed(TTCaptcha captcha, String code) {
                Log.d(TAG, "captcha check failed:" + code);
            }
            @Override
            public void error(TTCaptcha captcha, int code, String message) {
                Log.d(TAG, "captcha check error, code: " + code + ", message: " + message);
            }
        });
        captcha.show();
      說明

      驗證異常,表示在加載滑塊過程中檢測到異常情況。驗證失敗,表示用戶滑動結束后檢測異常情況。

      具體錯誤碼如下所示:

      • 1001:輸入參數錯誤。

      • 1002:網絡檢測異常。

      • 1003:js回調數據異常。

      • 1004:WebView加載異常。

      • 1005:js滑塊返回異常。

      • 1100:主動關閉滑塊。

最佳實踐示例

package com.aliyun.tigertally.apk;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

import com.aliyun.TigerTally.TigerTallyAPI;
import com.aliyun.TigerTally.captcha.api.TTCaptcha;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class DemoActivity extends AppCompatActivity {
    private final static String TAG = "TigerTally-Demo";

    private final static String APP_HOST = "******";
    private final static String APP_URL  = "******";
    private final static String APP_KEY  = "******";

    private final static OkHttpClient okHttpClient = new OkHttpClient();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);

        doTest();
    }

    private void doTest() {
        Log.d(TAG, "captcha flow");
        new Thread(() -> {
            // 初始化
            // 全量采集
            int ret = TigerTallyAPI.init(this, APP_KEY, TigerTallyAPI.CollectType.DEFAULT, null, null);
            // 不采集隱私字段
            // int ret = TigerTallyAPI.init(this, APP_KEY, TigerTallyAPI.CollectType.NOT_GRANTED, null, null);
            Log.d(TAG, "tiger tally init: " + ret);

            // 不能立即同步調用
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


            //  簽名
            String data = "hello world";
            String whash = null, wtoken = null;
            // 自定義加簽
            whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.POST, data.getBytes());
            wtoken = TigerTallyAPI.vmpSign(1, whash.getBytes());
            Log.d(TAG, "tiger tally vmp: " + whash + ", " + wtoken);

            // 正常加簽
            // wtoken = TigerTallyAPI.vmpSign(1, data.getBytes());
            // Log.d(TAG, "tiger tally vmp: " + wtoken);


            // 請求接口
            doPost(APP_URL, APP_HOST, whash, wtoken, data, (code, cookie, body) -> {
                // 判斷是否需要顯示滑塊
                int recheck = TigerTallyAPI.cptCheck(cookie, body);
                Log.d(TAG, "captcha check result: " + recheck);

                if (recheck == 0) return;
                this.runOnUiThread(this::doShow);
            });
        }).start();
    }

    // 顯示滑塊
    public void doShow() {
        Log.d(TAG, "captcha show");

        TTCaptcha.TTOption option = new TTCaptcha.TTOption();
        // option.customUri = "file:///android_asset/ali-tt-captcha-demo.html";
        // option.traceId    = "4534534534adf433534534543";
        option.titleText  = "測試 Title";
        option.descText   = "測試 Description";
        option.language   = "cn";
        option.cancelable = true;
        option.hideError  = true;
        option.slideColor = "#007FFF";

        TTCaptcha captcha = TigerTallyAPI.cptCreate(this, option, new TTCaptcha.TTListener() {
            @Override
            public void success(TTCaptcha captcha, String data) {
                Log.d(TAG, "captcha check success:" + data);
                captcha.dismiss();
            }

            @Override
            public void failed(TTCaptcha captcha, String code) {
                Log.d(TAG, "captcha check failed:" + code);
            }

            @Override
            public void error(TTCaptcha captcha, int code, String message) {
                Log.d(TAG, "captcha check error, code: " + code + ", message: " + message);
            }
        });

        captcha.show();
    }

    // 發送請求
    public static void doPost(String url, String host, String whash, String wtoken, String body, Callback callback) {
        Log.d(TAG, "start request post");

        int responseCode = 0;
        String responseBody = "";
        StringBuilder responseCookie = new StringBuilder();
        try {
            Request.Builder builder = new Request.Builder()
                    .url(url)
                    .addHeader("wToken", wtoken)
                    .addHeader("Host",   host)
                    .post(RequestBody.create(MediaType.parse("text/x-markdown"), body.getBytes()));

            if (whash != null) {
                builder.addHeader("ali_sign_whash", whash);
            }
            Response response = okHttpClient.newCall(builder.build()).execute();

            responseCode = response.code();
            responseBody = response.body() == null ? "" : response.body().string();
            for (String item : response.headers("Set-Cookie")) {
                responseCookie.append(item).append(";");
            }

            Log.d(TAG, "response code:" + responseCode);
            Log.d(TAG, "response cookie:" + responseCookie);
            Log.d(TAG, "response body:" + (responseBody.length() > 100 ? responseBody.substring(0, 100) : ""));

            if (response.isSuccessful()) {
                Log.d(TAG, "success: " + response.code() + ", " + response.message());
            } else {
                Log.e(TAG, "failed: " + response.code() + ", " + response.message());
            }

            response.close();
        } catch (Exception e) {
            e.printStackTrace();
            responseCode = -1;
            responseBody = e.toString();
        } finally {
            if (callback != null) {
                callback.onResponse(responseCode, responseCookie.toString(), responseBody);
            }
        }
    }

    public interface Callback {
        void onResponse(int code, String cookie, String body);
    }
}