Para configurar políticas de mitigación basadas en escenarios para su aplicación en la consola de Bot Management, debe integrar el App Protection SDK de Web Application Firewall (WAF). En este tema se describe cómo integrar el App Protection SDK con una aplicación iOS.
Contexto
El App Protection SDK firma las solicitudes que provienen del cliente de la aplicación. Después, el servidor de WAF verifica la firma de la solicitud para identificar y bloquear peticiones maliciosas. De esta manera, protege su aplicación.
Límites
-
El SDK de iOS está disponible en dos versiones: una con Identifier for Advertising (IDFA) y otra sin IDFA. Los archivos correspondientes del SDK son los siguientes:
AliTigerTally_IDFA.framework
AliTigerTally_NOIDFA.framework
Si su proyecto de iOS utiliza IDFA, se recomienda integrar la versión AliTigerTally_IDFA del SDK. De lo contrario, utilice la versión AliTigerTally_NOIDFA.
La interfaz
initpuede consumir bastante tiempo. Para obtener una protección óptima, espere como mínimo 2 segundos después de llamar a la interfazinitantes de invocar la interfazvmpSign. Este retraso no es obligatorio, pero un intervalo más corto podría impedir que las funciones de seguridad surtan efecto por completo. Ajuste el intervalo según sus necesidades de negocio.El App Protection SDK requiere la versión 9.0 de iOS o posterior.
Requisitos previos
-
Obtuvo el SDK para su aplicación iOS.
Para obtener el SDK, envíe un ticket para comunicarse con un experto técnico del producto.
NotaEl archivo del SDK para una aplicación iOS se llama
tigertally-X.Y.Z-xxxx-ios.zip, donde X.Y.Z es el número de versión. El archivo contiene dos archivos framework y dos archivos xcframework. -
Obtuvo la clave de autenticación del SDK (también conocida como appkey).
Una vez que habilite Bot Management, podrá iniciar sesión en la consola de Web Application Firewall 3.0. En la barra de menús superior, seleccione el resource group y la región (Chinese Mainland o Outside Chinese Mainland) de la instancia de WAF.. En el panel de navegación izquierdo, elija . Vaya a la pestaña App Protection y haga clic en Obtain and Copy AppKey en la esquina superior derecha para recuperar la clave de autenticación del SDK. Esta clave es obligatoria para inicializar el SDK y debe incluirse en su código de integración.
NotaCada cuenta de Alibaba Cloud tiene un appkey único para todos los nombres de dominio protegidos por WAF. Este appkey se utiliza para integrar el SDK en aplicaciones Android, iOS y HarmonyOS.
Ejemplo de clave de autenticación:
****OpKLvM6zliu6KopyHIhmneb_****u4ekci2W8i6F9vrgpEezqAzEzj2ANrVUhvAXMwYzgY_****vc51aEQlRovkRoUhRlVsf4IzO9dZp6nN_****Wz8pk2TDLuMo4pVIQvGaxH3vrsnSQiK****.
Paso 1: Crear un proyecto
En Xcode, cree un proyecto de iOS mediante el asistente de configuración. A continuación se muestra la estructura de directorios del proyecto.
tigerdemo
tigerdemo
tool
AppDelegate.h
AppDelegate.m
ViewController.h
ViewController.m
main.m
Main.storyboard
LaunchScreen.storyboard
AliTigerTallyApp.entitlements
Info.plist
Paso 2: Integrar el framework
Agregue el archivo del SDK, AliTigerTally_IDFA.framework o AliTigerTally_NOIDFA.framework, a su proyecto.
-
Versión IDFA
Después de agregar el archivo, establezca la opción Embed de AliTigerTally_IDFA.framework en Do Not Embed.
-
Versión sin IDFA
Agregue AliTigerTally_NOIDFA.framework a la sección Frameworks, Libraries, and Embedded Content de su proyecto y establezca Embed en Do Not Embed.
Agregue el archivo del SDK del módulo Captcha, AliCaptcha.framework, a su proyecto y establezca su opción Embed en Do Not Embed.
Agregue el archivo de recursos AliCaptcha.bundle a su proyecto desde Build Phases > Copy Bundle Resources.
Paso 3: Agregar bibliotecas de dependencias
En la sección Frameworks, Libraries, and Embedded Content de su proyecto de Xcode, agregue a continuación las bibliotecas de dependencias.
|
Biblioteca de dependencia |
Obligatoria para IDFA |
Obligatoria para la versión sin IDFA |
|
libc++.tbd |
Sí |
Sí |
|
libresolv.9.tbd |
Sí |
Sí |
|
CoreTelephony.framework |
Sí |
Sí |
|
AdSupport.framework |
Sí |
No |
|
AppTrackingTransparency.framework |
Sí |
No |
Paso 4: Agregar una marca del vinculador
En Build Settings, busque Other Linker Flags y agregue la marca -ObjC.
Paso 5: Agregar el código de integración
1. Agregar el archivo de encabezado
-
Para la versión IDFA, agregue la siguiente instrucción de importación:
#import <AliTigerTally_IDFA/AliTigerTally.h> -
Para la versión sin IDFA, agregue la siguiente instrucción de importación:
#import <AliTigerTally_NOIDFA/AliTigerTally.h>
2. Configurar la firma de datos
-
Establezca un identificador personalizado de usuario final para su negocio. Esto le permite configurar las políticas de protección de WAF con mayor flexibilidad.
/** * Sets the user account. * * @param account The account information. */ - (void)setAccount:(NSString *)account;-
Parámetros:
account: Tipo: NSString. Una cadena que identifica a un usuario. Se recomienda utilizar un formato anonimizado.
Valor devuelto: Ninguna.
-
Ejemplo:
// For guest users, you can skip setAccount and initialize directly. After a user logs in, call setAccount and re-initialize. [[AliTigerTally sharedInstance] setAccount:@"testAccount"];
-
-
Inicialice el SDK para recopilar datos.
Cada inicialización recopila la información del dispositivo una sola vez. Llame de nuevo a la función init para reinicializar la recopilación de datos en distintos escenarios de negocio.
La inicialización admite tres modos de recopilación de datos: completo, de privacidad personalizada y sin privacidad. El modo sin privacidad excluye los campos relacionados con la privacidad del usuario final, como IDFA e IDFV.
NotaPara cumplir con sus requisitos internos, seleccione un modo de recopilación de datos adecuado que garantice la integridad de la información. Entre más completos sean los datos, mejor será la detección de amenazas.
// Initialization callback. Returns the status code of the interface call. typedef void (^TTInitListener)(int); /** * Initializes the SDK. * * @param appkey The key. * @param options Optional parameters. * @param onInitFinish The callback for when initialization is complete. * @return Indicates whether the initialization was successful. */ - (int)init:(NSString *)appkey collectType:(TTCollectType)type options:(NSMutableDictionary *_Nullable)options listener:(TTInitListener _Nullable)onInitFinish;-
Parámetros:
appkey: Tipo: NSString. Su clave de autenticación del SDK.
-
collectType: Tipo: TTCollectType. El modo de recopilación de datos. Valores válidos:
Campo
Descripción
Ejemplo
TT_DEFAULT
Recopila todos los datos.
TT_DEFAULT
TT_NO_BASIC_DATA
No recopila datos básicos del dispositivo.
Esto incluye el nombre del dispositivo, la versión del sistema operativo y la resolución de pantalla.
TT_NO_X | TT_NO_Y
(donde X e Y representan los tipos de campos de datos que se excluirán)
TT_NO_UNIQUE_DATA
No recopila datos de identificadores únicos.
Esto incluye IDFV e IDFA.
TT_NO_EXTRA_DATA
No recopila datos extendidos del dispositivo.
Esto incluye la información de Wi-Fi conectada (SSID, BSSID) y la lista de redes Wi-Fi cercanas.
TT_NOT_GRANTED
No recopila ninguno de los datos anteriores relacionados con la privacidad.
TT_NOT_GRANTED
-
options: Tipo: NSMutableDictionary. Parámetros opcionales para la recopilación de datos. El valor predeterminado es nil. Están disponibles los siguientes parámetros:
Campo
Descripción
Ejemplo
IPv6
Especifica si se utiliza un nombre de dominio IPv6 para reportar la información del dispositivo.
0 (predeterminado): Utiliza un nombre de dominio IPv4.
1: Utiliza un nombre de dominio IPv6.
1
Intl
Especifica si se utiliza un nombre de dominio fuera de China continental para reportar la información del dispositivo.
0 (predeterminado): Reporta a China continental.
1: Reporta a regiones fuera de China continental.
1
CustomUrl
Establece el nombre de dominio del servidor de reporte de datos.
https://cloudauth-device.us-west-1.aliyuncs.com
CustomHost
Establece el host del servidor de reporte de datos.
cloudauth-device.us-west-1.aliyuncs.com
NotaPara la mayoría de los sitios internacionales, configure únicamente el parámetro Intl. Si necesita reportar datos a un sitio específico, configure los parámetros CustomUrl y CustomHost. Los sitios disponibles incluyen:
Si
Intlse establece en0, los datos se reportan al sitio predeterminado en China (Shanghai): https://cloudauth-device.cn-shanghai.aliyuncs.com-
Si
Intlse establece en1:El sitio predeterminado es Singapore: https://cloudauth-device.ap-southeast-1.aliyuncs.com
Indonesia (Jakarta): https://cloudauth-device.ap-southeast-5.aliyuncs.com
US (Silicon Valley): https://cloudauth-device.us-west-1.aliyuncs.com
Germany (Frankfurt): https://cloudauth-device.eu-central-1.aliyuncs.com
China (Hong Kong): https://cloudauth-device.cn-hongkong.aliyuncs.com
-
listener: Tipo: TTInitListener. La interfaz de devolución de llamada de inicialización del SDK. Esta devolución de llamada sirve para determinar el estado de la inicialización. El valor predeterminado es nil.
TTCode
Código
Descripción
TT_SUCCESS
0
Inicialización exitosa.
TT_NOT_INIT
-1
El SDK no está inicializado.
TT_NOT_PERMISSION
-2
No se otorgaron los permisos obligatorios de iOS.
TT_UNKNOWN_ERROR
-3
Ocurrió un error desconocido del sistema.
TT_NETWORK_ERROR
-4
Ocurrió un error de red.
TT_NETWORK_ERROR_EMPTY
-5
Ocurrió un error de red. El contenido devuelto es una cadena vacía.
TT_NETWORK_ERROR_INVALID
-6
El formato de la respuesta de red no es válido.
TT_PARSE_SRV_CFG_ERROR
-7
Error al analizar sintácticamente la configuración del servidor.
TT_NETWORK_RET_CODE_ERROR
-8
La puerta de enlace devolvió una respuesta con errores.
TT_APPKEY_EMPTY
-9
El appkey está vacío.
TT_PARAMS_ERROR
-10
Ocurrieron otros errores de parámetros.
TT_FGKEY_ERROR
-11
Ocurrió un error de cálculo de clave.
TT_APPKEY_ERROR
-12
La versión del SDK no coincide con la versión del appkey.
Valor devuelto: Tipo: int. Un código de error.
0indica éxito y un número negativo indica un fallo.-
Ejemplo:
// The appkey is the authentication key assigned to you on the Alibaba Cloud console. NSString *appKey = @"xxxxxxxxxxxxxxxxxxxxx"; // Optional parameters. You can configure IPv6 and reporting from outside the Chinese mainland. NSMutableDictionary *options = [[NSMutableDictionary alloc] init]; [options setValue:@"0" forKey:@"IPv6"]; // Use IPv4. [options setValue:@"0" forKey:@"Intl"]; // Report data from within the Chinese mainland. // [options setValue:@"1" forKey:@"Intl"]; // Report data from outside the Chinese mainland. // Report data to the US (West) region. // [options setValue:@"https://cloudauth-device.us-west-1.aliyuncs.com" forKey:@"CustomUrl"]; // [options setValue:@"cloudauth-device.us-west-1.aliyuncs.com" forKey:@"CustomHost"]; // An initialization call collects device information once. You can call the init function again to collect information for different business scenarios. // Full data collection. if (0 == [[AliTigerTally sharedInstance] init:appkey collectType:TT_DEFAULT options:options listener:nil]) { NSLog(@"Initialization successful"); } else { NSLog(@"Initialization failed"); } // To collect specific types of private data, use the "|" operator to specify multiple types. TTCollectType collectPrivacy = TT_NO_BASIC_DATA | TT_NO_EXTRA_DATA; int ret = [[AliTigerTally sharedInstance] init:appkey collectType:collectPrivacy options:options listener:nil]; // Do not collect private data. int ret = [[AliTigerTally sharedInstance] init:appkey collectType:TT_NOT_GRANTED options:options listener:nil];
-
-
Generación de hash de datos.
Esta interfaz de firma personalizada genera un hash de los datos de entrada para producir una cadena
whash, la cual funciona como una firma personalizada. Para las solicitudes POST, PUT y PATCH, utilice el cuerpo de la solicitud como entrada. Para las solicitudes GET y DELETE, utilice la URL completa. Además, debe agregar la cadenawhashgenerada al campo ali_sign_whash en el encabezado de la solicitud HTTP.// Request type: typedef NS_ENUM(NSInteger, TTRequestType) { TT_GET=0, TT_POST, TT_PUT, TT_PATCH, TT_DELETE }; /** * Hashes the custom signature data. * @param type The data type. * @param input The data to be signed. * @return The whash string. */ - (NSString *)vmpHash:(TTRequestType)type input:(NSData *)input;-
Parámetros:
-
type: Tipo: TTTypeRequest. El tipo de datos. Valores válidos:
GET: Datos de solicitud GET.
POST: Datos de solicitud POST.
PUT: Datos de solicitud PUT.
PATCH: Datos de solicitud PATCH.
DELETE: Datos de solicitud DELETE.
input: Tipo: NSData. Los datos que se firmarán. Pase el cuerpo o la URL según el tipo.
-
Valor devuelto: Tipo: NSString. La cadena
whash.-
Ejemplo:
// GET request NSString *url = @"https://tigertally.aliyun.com/apptest"; NSString *whash = [[AliTigerTally sharedInstance] vmpHash:TT_GET input:[url dataUsingEncoding:NSUTF8StringEncoding]]; NSLog(@"whash: %@", whash); // POST request NSString *body = @"hello world"; NSString *whash = [[AliTigerTally sharedInstance] vmpHash:TT_POST input:[body dataUsingEncoding:NSUTF8StringEncoding]]; NSLog(@"whash: %@", whash);
NotaSolo es necesario llamar a esta interfaz si habilitó la opción de firma personalizada en la consola de WAF. Si utiliza la configuración de firma predeterminada, omita este paso.
-
-
Firma de datos.
Este método utiliza tecnología VMP para firmar los datos de entrada y devuelve una cadena
wtokenpara la autenticación de la solicitud./** * Signs the data. * @param input The data to be signed. * @return The wtoken string. */ - (NSString *)vmpSign:(NSData *)input;-
Parámetros:
input: Tipo: NSData. Los datos que se firmarán. Por lo general, se trata del cuerpo de la solicitud completo o del valor
whashobtenido con la firma personalizada.
Valor devuelto: Tipo: NSString. La cadena
wtoken.-
Ejemplo:
// Default signature configured in the console (custom signing is not selected). NSString *body = @"hello world"; NSString *wtoken = [[AliTigerTally sharedInstance] vmpSign:[body dataUsingEncoding:NSUTF8StringEncoding]]; NSLog(@"wtoken: %@", wtoken); // Custom signing configured in the console. // Custom signing for a POST request. NSString *whash = [[AliTigerTally sharedInstance] vmpHash:TT_POST input:[body dataUsingEncoding:NSUTF8StringEncoding]]; NSString *wtoken = [[AliTigerTally sharedInstance] vmpSign:[whash dataUsingEncoding:NSUTF8StringEncoding]]; NSLog(@"whash: %@, wtoken: %@", whash, wtoken); // Custom signing for a GET request. NSString *url = @"https://tigertally.aliyun.com/apptest"; NSString *whash = [[AliTigerTally sharedInstance] vmpHash:TT_GET input:[url dataUsingEncoding:NSUTF8StringEncoding]]; NSString *wtoken = [[AliTigerTally sharedInstance] vmpSign:[whash dataUsingEncoding:NSUTF8StringEncoding]]; NSLog(@"whash: %@, wtoken: %@", whash, wtoken);NotaCuando utilice la firma personalizada, la entrada de la interfaz vmpSign debe ser la cadena
whashgenerada por vmpHash. Al configurar una política basada en escenarios para App Protection, debe establecer el campo de firma personalizada enali_sign_whash.Cuando llame a vmpHash para generar un valor
whashen una solicitud GET, asegúrese de que la URL de entrada sea idéntica a la URL final de la solicitud de red. Preste especial atención a la codificación de la URL, ya que algunos frameworks codifican automáticamente ciertos caracteres o parámetros.La entrada de la interfaz vmpHash no puede ser una matriz de bytes ni una cadena vacía. Si la entrada es una URL, debe incluir una ruta o un parámetro.
Al llamar a vmpSign, si el cuerpo de la solicitud está vacío (por ejemplo, en una solicitud GET o en una solicitud POST sin cuerpo), pase
nilo la representación NSData de una cadena vacía, como[@"" dataUsingEncoding:NSUTF8StringEncoding].-
Si
whashowtokendevuelve alguna de las siguientes cadenas, significa que ocurrió un error:you must call init first: No se llamó a la función
init.you must input correct data: Los datos de entrada no son válidos.
you must input correct type: El tipo de entrada no es válido.
-
3. Verificación secundaria
-
Compruebe el resultado.
Para determinar si se requiere una verificación secundaria, compruebe la cookie y el cuerpo de la respuesta. Si el encabezado contiene varios campos Set-Cookie, combínelos en una sola cadena de cookies antes de llamar a esta interfaz.
/** * Checks whether to perform secondary verification. * * @param cookie The response cookie. * @param body The response body. * @return 0: Pass, 1: Secondary verification required. */ - (int)cptCheck:(NSString *)cookie body:(NSData *)body;-
Parámetros:
cookie: Tipo: NSString. Todas las cookies de la respuesta de la solicitud.
body: Tipo: NSData. El cuerpo completo de la respuesta de la solicitud.
Valor devuelto: Tipo: int. El resultado de la decisión.
0indica que la solicitud pasó la comprobación y1indica que se requiere una verificación secundaria.-
Ejemplo:
NSString *cookie = @"key1=value1;key2=value2;"; NSData *body = xxx; int recheck = [[AliTigerTally sharedInstance] cptCheck:cookie body:body]; NSLog(@"recheck: %d", recheck);
-
-
Cree un control deslizante.
Si el resultado de cptCheck indica que se necesita verificación, cree un objeto de control deslizante. El objeto TTCaptcha proporciona los métodos
showydismisspara controlar la ventana del control deslizante. Utilice TTOption para configurar sus parámetros y TTDelegate para gestionar las devoluciones de llamada de su estado. Para personalizar la ventana del control deslizante, debe proporcionar una URL hacia una página personalizada, la cual puede ser un archivo HTML local o una página remota./** * Displays the slider for verification. * * @param view The parent component. * @param option The parameters. * @param detegate The callback protocol. */ - (TTCaptcha *)cptCreate:(UIView *)view option:(TTOption *)option delegate:(id<TTDelegate>)detegate; @protocol TTDelegate <NSObject> @required // Slider verification is successful. - (void)success:(TTCaptcha *)captcha data:(NSString *)data; // Slider verification failed. - (void)failed:(TTCaptcha *)captcha code:(NSString *)code; @end @interface TTOption : NSObject // Tap to cancel. @property (nonatomic, assign) BOOL cancelable; // Custom page. @property (nonatomic, strong) NSString *customUri; // Language. @property (nonatomic, strong) NSString *language; @end @interface TTCaptcha : NSObject - (instancetype)init:(UIView *)view option:(TTOption *)option delegate:(id<TTDelegate>)delegate; // Obtains the slider traceId for data analytics. - (NSString *)getTraceId; // Displays the slider. - (void)show; // Dismisses the slider. - (void)dismiss; @end-
Parámetros:
view: Tipo: View. La vista de la página actual.
option: Tipo: TTOption. Los parámetros de configuración del control deslizante.
delegate: Tipo: TTDelegate. La devolución de llamada del estado del control deslizante.
Valor devuelto: Tipo: TTCaptcha. El objeto del control deslizante.
-
Ejemplo:
#pragma mark - TTDelegate - (void)failed:(TTCaptcha *)captcha code:(nonnull NSString *)code { NSLog(@"captcha failed: %@", code); } - (void)success:(TTCaptcha *)captcha data:(nonnull NSString *)data { NSLog(@"captcha success: %@", data); } TTOption *option = [[TTOption alloc] init]; // option.customUri = @"ali-tt-captcha-demo-ios"; option.language = @"cn"; option.cancelable = true; TTCaptcha *captcha = [[AliTigerTally sharedInstance] cptCreate:[self view] option:option delegate:self]; [captcha show];NotaUn error de "Verification failed" indica que se detectó una excepción durante o después de la interacción del usuario con el control deslizante.
En la siguiente tabla se describen los códigos de error.
1001: Error en el desafío de verificación.
1002: Ocurrió una excepción del sistema.
1003: Se especificó un parámetro no válido.
1005: Se canceló la verificación.
8001: Error al mostrar el control deslizante.
8002: Ocurrió una excepción en los datos de verificación del control deslizante.
8003: Ocurrió una excepción interna durante la verificación del control deslizante.
8004: Ocurrió un error de red.
-
Práctica recomendada
#import "DemoController.h"
#if __has_include(<AliTigerTally_NOIDFA/AliTigerTally_NOIDFA.h>)
#import <AliTigerTally_NOIDFA/AliTigerTally_NOIDFA.h>
#else
#import <AliTigerTally_IDFA/AliTigerTally_IDFA.h>
#endif
@interface DemoController () <TTDelegate>
@end
static NSString *kAppHost = @"******";
static NSString *kAppUrl = @"******";
static NSString *kAppkey = @"******";
@implementation DemoController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self doTest];
}
- (void)doTest {
NSThread *thread = [[NSThread alloc] initWithBlock:^{
// Initialize the SDK.
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
// [options setValue:@"1" forKey:@"Intl"]; // Configure for international reporting.
int code = [[AliTigerTally sharedInstance] init:kAppkey collectType:TT_DEFAULT options:options listener:nil];
NSLog(@"tigertally init: %d", code);
// Do not make a synchronous call immediately.
[NSThread sleepForTimeInterval:2.0];
// Generate the signature.
NSString *body = @"hello world";
NSString *whash = nil, *wtoken = nil;
// Custom signing.
whash = [[AliTigerTally sharedInstance] vmpHash:TT_Post input:[body dataUsingEncoding:NSUTF8StringEncoding]];
wtoken = [[AliTigerTally sharedInstance] vmpSign:[whash dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(@"tigertally vmp: %@, %@", whash, wtoken);
// Default signing.
// wtoken = [[AliTigerTally sharedInstance] vmpSign:[body dataUsingEncoding:NSUTF8StringEncoding]];
// NSLog(@"tigertally vmp: %@", wtoken);
[self doPost:kAppUrl host:kAppHost whash:whash wtoken:wtoken body:[body dataUsingEncoding:NSUTF8StringEncoding] callback:^(NSInteger code, NSString * _Nonnull cookie, NSData * _Nonnull body) {
int check = [[AliTigerTally sharedInstance] cptCheck:cookie body:body];
NSLog(@"captcha result:%d", check);
if (check == 0) return;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self doShow];
}];
}];
}];
[thread start];
}
- (void)doShow {
NSLog(@"captcha show");
TTOption *option = [[TTOption alloc] init];
// option.customUri = @"ali-tt-captcha-demo-ios";
option.language = @"cn";
option.cancelable = true;
TTCaptcha *captcha = [[AliTigerTally sharedInstance] cptCreate:[self view] option:option delegate:self];
[captcha show];
}
- (void)doPost:(NSString *)url host:(NSString *)host whash:(NSString *)whash wtoken:(NSString *)wtoken body:(NSData *)body callback:(void(^)(NSInteger code, NSString* cookie, NSData *body))callback {
NSLog(@"start reqeust post");
NSURL* requestUrl = [NSURL URLWithString: url];
NSData* requestBody = body;
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
[request setValue: @"text/x-markdown" forHTTPHeaderField: @"Content-Type"];
[request setValue: host forHTTPHeaderField: @"HOST"];
[request setValue: wtoken forHTTPHeaderField:@"wToken"];
if (whash) {
[request setValue:whash forHTTPHeaderField:@"ali_sign_whash"];
}
request.HTTPMethod = @"post";
request.HTTPBody = requestBody;
NSURLSessionDataTask* dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"tiger tally sign failed: %@", [error description]);
callback(-1, nil, [[error description] dataUsingEncoding:NSUTF8StringEncoding]);
return;
}
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
NSInteger code = httpResponse.statusCode;
NSString* body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSMutableString* cookies = [[NSMutableString alloc] init];
for (NSHTTPCookie* cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
if ([url containsString:[cookie domain]]) {
NSLog(@"domain:%@, path: %@, name:%@, value: %@", [cookie domain], [cookie path], [cookie name], [cookie value]);
[cookies appendFormat: @"%@=%@;", [cookie name], [cookie value]];
}
}
NSLog(@"reponse code: %ld", code);
NSLog(@"reponse cookie: %@", cookies);
NSLog(@"reponse body: %@", body ? (body.length > 100 ? [body substringToIndex:100]:body) : @"");
callback(code, cookies, data);
}];
[dataTask resume];
}
#pragma mark - TTDelegate
- (void)failed:(TTCaptcha *)captcha code:(nonnull NSString *)code {
NSLog(@"captcha failed: %@", code);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:code preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:true completion:nil];
}
- (void)success:(TTCaptcha *)captcha data:(nonnull NSString *)data {
NSLog(@"captcha success: %@", data);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:data preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:true completion:nil];
}
@end