iOS中的NSURLConnection和基本HTTP身份验证

Ale*_*ove 84 iphone objective-c nsurlconnection ios

我需要GET HTTP request用Basic 调用一个初始化Authentication.这将是第一次将请求发送到服务器并且我已经拥有了username & password这样的服务,因此不需要服务器进行授权的质询.

第一个问题:

  1. 是否NSURLConnection必须设置为同步才能执行Basic Auth?根据这篇文章的答案,如果你选择异步路由,似乎你不能做Basic Auth.

  2. 任何人都知道任何一些示例代码,说明了基本GET request身份验证,而无需质询响应?Apple的文档显示了一个示例,但仅在服务器向客户端发出质询请求之后.

我是SDK的新网络部分,我不确定我应该使用哪个其他类来实现这个功能.(我看到了NSURLCredential类,但它似乎只NSURLAuthenticationChallenge在客户端请求来自服务器的授权资源之后才使用它).

cat*_*sby 130

我正在使用与MGTwitterEngine的异步连接,并在NSMutableURLRequest(theRequest)中设置授权,如下所示:

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"];
Run Code Online (Sandbox Code Playgroud)

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

  • 自iOS 7.0和OS X 10.9以来,不推荐使用@bickster`base64Encoding`.我使用`[authData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]`.另外还有`NSDataBase64Encoding64CharacterLineLength`或`NSDataBase64Encoding76CharacterLineLength` (11认同)
  • 对于base64编码(`[authData base64EncodedString]`),将Matt Gallagher的NSData + Base64.h和.m文件添加到您的XCode-Project([Mac和iPhone上的Base64编码选项](http://cocoawithlove.com) /2009/06/base64-encoding-options-on-mac-and.html)). (7认同)
  • NS64上的2014年不存在base64EncodingWithLineLength.请改用base64Encoding. (4认同)
  • NSASCIIStringEncoding将破坏非usascii用户名或密码.请改用NSUTF8StringEncoding (3认同)
  • 我没有写一个部分,它只是MGTwitterEngine的一部分,来自添加到NSData的类别.请参阅NSData + Base64.h/m:http://github.com/ctshryock/MGTwitterEngine (2认同)

dom*_*dom 80

即使问题得到解答,我想提出解决方案,它不需要外部库,我在另一个线程中找到:

// 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 {
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 这与其他解决方案并不完全相同:它首先联系服务器,接收401响应,然后使用正确的凭据进行响应.所以你浪费了一次往返.从好的方面来说,您的代码将处理其他挑战,例如HTTP Digest Auth.这是一种权衡. (9认同)
  • 无论如何,这是做到这一点的"正确方法".所有其他方式都是捷径. (2认同)

小智 12

以下是没有第三方参与的详细答案:

请点击这里:

//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];
      }
}]
Run Code Online (Sandbox Code Playgroud)

请告诉我您对此的反馈.

谢谢


Luk*_*uke 7

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

要base64编码用户名和密码,所以替换

NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]];
Run Code Online (Sandbox Code Playgroud)

NSString *encodedLoginData = [Base64 encode:[loginString dataUsingEncoding:NSUTF8StringEncoding]];
Run Code Online (Sandbox Code Playgroud)

您需要包含以下文件

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
Run Code Online (Sandbox Code Playgroud)