finished - NSURLConnection y Autenticación HTTP básica en iOS
nsurlconnection error codes (7)
¿Puede decirme cuál es la razón detrás de limitar la longitud de la línea de codificación a 80 en su código de ejemplo? Pensé que los encabezados HTTP tienen una longitud máxima de algo así como 4k (o tal vez algunos servidores no toman más tiempo que eso). - Justin Galzic 29 de diciembre de 2009 a las 17:29
No es una limitación de 80, es una opción del método base64EncodingWithLineLength en NSData + Base64.h / m, donde puede dividir la cadena codificada en varias líneas, lo que es útil para otras aplicaciones, como la transmisión nntp. Creo que el autor del motor de Twitter elige 80 para que sea lo suficientemente grande como para acomodar la mayoría de los resultados codificados por usuario / contraseña en una línea.
Necesito invocar una GET HTTP request
inicial con Authentication
básica. Esta sería la primera vez que se envía la solicitud al servidor y ya tengo el username & password
por lo que no es necesario que el servidor solicite autorización.
Primera pregunta:
¿
NSURLConnection
debe establecerse como síncrono para realizar Authentic básico? Según la respuesta en esta post , parece que no puedes hacer Basic Auth si optas por la ruta asíncrona.¿Alguien sabe de algún código de muestra que ilustra la autenticación básica en una
GET request
sin la necesidad de una respuesta de desafío? La documentación de Apple muestra un ejemplo, pero solo después de que el servidor haya emitido la solicitud de desafío al cliente.
Soy un poco nuevo en la parte de redes del SDK y no estoy seguro de cuál de las otras clases debería usar para que funcione. (Veo la clase de NSURLCredential
pero parece que solo se usa con NSURLAuthenticationChallenge
después de que el cliente haya solicitado un recurso autorizado del servidor).
Aquí hay una respuesta detallada sin participación de terceros:
Por favor revisa aquí:
//username and password value
NSString *username = @“your_username”;
NSString *password = @“your_password”;
//HTTP Basic Authentication
NSString *authenticationString = [NSString stringWithFormat:@"%@:%@", username, password]];
NSData *authenticationData = [authenticationString dataUsingEncoding:NSASCIIStringEncoding];
NSString *authenticationValue = [authenticationData base64Encoding];
//Set up your request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.your-api.com/“]];
// Set your user login credentials
[request setValue:[NSString stringWithFormat:@"Basic %@", authenticationValue] forHTTPHeaderField:@"Authorization"];
// Send your request asynchronously
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *responseCode, NSData *responseData, NSError *responseError) {
if ([responseData length] > 0 && responseError == nil){
//logic here
}else if ([responseData length] == 0 && responseError == nil){
NSLog(@"data error: %@", responseError);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"Error accessing the data" delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}else if (responseError != nil && responseError.code == NSURLErrorTimedOut){
NSLog(@"data timeout: %@”, NSURLErrorTimedOut);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"connection timeout" delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}else if (responseError != nil){
NSLog(@"data download error: %@”,responseError);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"data download error" delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}
}]
Por favor, háganme saber sus comentarios sobre esto.
Gracias
Como NSData :: dataUsingEncoding está en desuso (ios 7.0), puede usar esta solución:
// Forming string with credentials ''myusername:mypassword''
NSString *authStr = [NSString stringWithFormat:@"%@:%@", username, password];
// Getting data from it
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
// Encoding data with base64 and converting back to NSString
NSString* authStrData = [[NSString alloc] initWithData:[authData base64EncodedDataWithOptions:NSDataBase64EncodingEndLineWithLineFeed] encoding:NSASCIIStringEncoding];
// Forming Basic Authorization string Header
NSString *authValue = [NSString stringWithFormat:@"Basic %@", authStrData];
// Assigning it to request
[request setValue:authValue forHTTPHeaderField:@"Authorization"];
Estoy usando una conexión asíncrona con MGTwitterEngine y establece la autorización en NSMutableURLRequest
( theRequest
) de esta manera:
NSString *authStr = [NSString stringWithFormat:@"%@:%@", [self username], [self password]];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]];
[theRequest setValue:authValue forHTTPHeaderField:@"Authorization"];
No creo que este método requiera pasar por el ciclo de desafío, pero podría estar equivocado
Incluso si se responde la pregunta, quiero presentar la solución, que no requiere libs externos, encontré en otro hilo:
// Setup NSURLConnection
NSURL *URL = [NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:URL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
[connection release];
// NSURLConnection Delegates
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] == 0) {
NSLog(@"received authentication challenge");
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:@"USER"
password:@"PASSWORD"
persistence:NSURLCredentialPersistenceForSession];
NSLog(@"credential created");
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
NSLog(@"responded to authentication challenge");
}
else {
NSLog(@"previous authentication failure");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
...
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
...
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
...
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
...
}
Si está utilizando GTMHTTPFetcher para su conexión, la autenticación básica es bastante fácil también. Simplemente debe proporcionar la credencial al buscador antes de comenzar la búsqueda.
NSString * urlString = @"http://www.testurl.com/";
NSURL * url = [NSURL URLWithString:urlString];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
NSURLCredential * credential = [NSURLCredential credentialWithUser:@"username" password:@"password" persistence:NSURLCredentialPersistenceForSession];
GTMHTTPFetcher * gFetcher = [GTMHTTPFetcher fetcherWithRequest:request];
gFetcher.credential = credential;
[gFetcher beginFetchWithDelegate:self didFinishSelector:@selector(fetchCompleted:withData:andError:)];
Si no desea importar todo MGTwitterEngine y no está haciendo una solicitud asíncrona, puede utilizar http://www.chrisumbel.com/article/basic_authentication_iphone_cocoa_touch
Para base64 codifique el nombre de usuario y la contraseña, así que reemplace
NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]];
con
NSString *encodedLoginData = [Base64 encode:[loginString dataUsingEncoding:NSUTF8StringEncoding]];
después
Deberás incluir el siguiente archivo
static char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@implementation Base64
+(NSString *)encode:(NSData *)plainText {
int encodedLength = (((([plainText length] % 3) + [plainText length]) / 3) * 4) + 1;
unsigned char *outputBuffer = malloc(encodedLength);
unsigned char *inputBuffer = (unsigned char *)[plainText bytes];
NSInteger i;
NSInteger j = 0;
int remain;
for(i = 0; i < [plainText length]; i += 3) {
remain = [plainText length] - i;
outputBuffer[j++] = alphabet[(inputBuffer[i] & 0xFC) >> 2];
outputBuffer[j++] = alphabet[((inputBuffer[i] & 0x03) << 4) |
((remain > 1) ? ((inputBuffer[i + 1] & 0xF0) >> 4): 0)];
if(remain > 1)
outputBuffer[j++] = alphabet[((inputBuffer[i + 1] & 0x0F) << 2)
| ((remain > 2) ? ((inputBuffer[i + 2] & 0xC0) >> 6) : 0)];
else
outputBuffer[j++] = ''='';
if(remain > 2)
outputBuffer[j++] = alphabet[inputBuffer[i + 2] & 0x3F];
else
outputBuffer[j++] = ''='';
}
outputBuffer[j] = 0;
NSString *result = [NSString stringWithCString:outputBuffer length:strlen(outputBuffer)];
free(outputBuffer);
return result;
}
@end