iOS中的NSURLConnection和基本HTTP身份validation

我需要使用基本Authentication调用初始GET HTTP request 。 这将是第一次请求被发送到服务器,我已经有了username & password所以没有必要从服务器的授权挑战。

第一个问题:

  1. NSURLConnection是否必须设置为同步进行基本身份validation? 根据这篇文章的答案,如果你select了asynchronous路由,似乎你不能进行基本身份validation。

  2. 任何人都知道任何一个示例代码,说明GET request基本身份validation,而不需要质询响应? 苹果的文档显示了一个例子,但只有在服务器已经向客户端发出挑战请求之后。

我有点新的SDK的networking部分,我不知道我应该用哪个其他类来得到这个工作。 (我看到了NSURLCredential类,但似乎只有在客户端向服务器请求授权资源后,才使用NSURLAuthenticationChallenge )。

我正在使用与MGTwitterEngine的asynchronous连接,它在NSMutableURLRequesttheRequest )中设置授权,如下所示:

 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"]; 

我不相信这种方法需要经历挑战循环,但我可能是错的

即使是这个问题的答案,我想提出的解决scheme,这不需要外部库,我发现在另一个线程:

 // 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 { ... } 

这里是一个没有涉及第三方的详细答案:

请检查这里:

 //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]; } }] 

请让我知道你对此的反馈。

谢谢

如果您不想导入整个MGTwitterEngine,并且您没有执行asynchronous请求,那么您可以使用http://www.chrisumbel.com/article/basic_authentication_iphone_cocoa_touch

以base64编码的用户名和密码,所以更换

 NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]]; 

 NSString *encodedLoginData = [Base64 encode:[loginString dataUsingEncoding:NSUTF8StringEncoding]]; 

您将需要包含以下文件

 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 

由于NSData :: dataUsingEncoding已被弃用(IOS 7.0),你可以使用这个解决scheme:

 // 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"]; 

如果您使用GTMHTTPFetcher进行连接,则基本身份validation也相当容易。 您只需在开始提取前提供凭证给提取器。

 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:)]; 

你能告诉我在你的代码中将编码行长度限制为80的原因是什么? 我认为HTTP标头的最大长度是4k(或者某些服务器不需要比这更长的时间)。 – 贾斯汀Galzic 09年12月29日在17:29

它不限于80,它是NSData + Base64.h / m中的base64EncodingWithLineLength方法的一个选项,您可以将编码的string拆分为多行,这对其他应用程序(如nntp传输)很有用。 我相信80被Twitter引擎作者select为一个足够大的长度来容纳大多数用户/密码编码结果到一行。