2012-10-10 7 views
12

Nói chung tôi muốn chỉ "cháy và quên" bằng phương thức lớp sendAsynchronousRequest của NSURL bằng cách sử dụng khối xử lý hoàn thành nhưng có vẻ như đó không phải là tùy chọn khi cần xác thực.Xác thực bằng NSURLConnection sendAsynchronousRequest với trình xử lý hoàn thành

Khi sử dụng một yêu cầu phong cách xử lý hoàn thành như thế này:

[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.mysite.com/"]] 
             queue:[NSOperationQueue mainQueue] 
          completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 


          //Do Stuff 

          }]; 

cách thích hợp để xử lý xác thực là gì? Tôi có cần phân bổ và khởi động NSURLConnection và thiết lập một đại biểu thay vì sử dụng kiểu phương thức lớp này không? Tôi nghĩ rằng tôi hiểu làm thế nào để xác thực một cách chính xác với chức năng đại biểu nhưng tôi đang cố gắng tìm ra nếu tôi có thể bao gồm trong khối completionHandler hoặc nếu có một cách tốt hơn để làm điều này.

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
{ 

    if ([challenge previousFailureCount] > 0) { 
     NSLog(@"Authentication Failure"); 
     [connection cancel]; 
    } 
    else 
    { 

     NSURLCredential *credential = [NSURLCredential credentialWithUser:self.username 
                   password:self.password 
                   persistence:NSURLCredentialPersistenceForSession]; 
     [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; 
    } 

} 

Trả lời

22

Tôi nghĩ phương pháp completionHandler là dành cho các yêu cầu cơ bản. Có lẽ bạn có thể xem xét sử dụng AFNetworking khi tôi sử dụng điều này với phương pháp chặn và xác thực.

EDIT .... Bạn đã thử thêm tiêu đề xác thực vào NSURLRequest chưa? Tạo một NSMutableURLRequest:

NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.example.com/"]]; 

Và thêm tiêu đề xác thực như thế này:

NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", userName, password]; 
NSString *authValue = [NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)]; 
[urlRequest setValue:authValue forHTTPHeaderField:@"Authorization"]; 

Chức năng AFBase64EncodedStringFromString là thế này:

static NSString * AFBase64EncodedStringFromString(NSString *string) { 
    NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]]; 
    NSUInteger length = [data length]; 
    NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2)/3) * 4]; 

    uint8_t *input = (uint8_t *)[data bytes]; 
    uint8_t *output = (uint8_t *)[mutableData mutableBytes]; 

    for (NSUInteger i = 0; i < length; i += 3) { 
     NSUInteger value = 0; 
     for (NSUInteger j = i; j < (i + 3); j++) { 
      value <<= 8; 
      if (j < length) { 
       value |= (0xFF & input[j]); 
      } 
     } 

     static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/"; 

     NSUInteger idx = (i/3) * 4; 
     output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F]; 
     output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F]; 
     output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '='; 
     output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '='; 
    } 

    return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding]; 
} 

Sau đó gọi hàm bạn gọi trước, nhưng sử dụng NSURLRequest mới của bạn:

[NSURLConnection sendAsynchronousRequest:urlRequest 
    queue:[NSOperationQueue mainQueue] 
    completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 

}]; 
+0

'AFBase64EncodedStringFromString' là một chức năng riêng và không được sử dụng bởi chính nó. Thay vào đó, bạn có thể thực hiện 'AFHTTPClient setAuthorizationHeaderWithUsername: password:' và tạo một 'NSURLRequest' với' -requestWithMethod: path: parameters: '(hoặc chỉ cần sao chép phần đầu ủy quyền từ yêu cầu được tạo ra) – mattt

+3

Phải có cách để đạt được điều này mà không cần Thư viện của bên thứ ba ... – dan

21

Mặc dù vấn đề này được giải quyết trong một thời gian bây giờ, tôi muốn thêm một giải pháp mà doesn `t yêu cầu thứ 3 thư viện của bên:

//HTTP Authentication 
NSString *authStr = [NSString stringWithFormat:@"%@:%@", @"Username", @"Password"]]; 
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding]; 
NSString *authValue = [authData base64Encoding]; 

//Set up Request: 
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init]; 
[request setURL:[NSURL URLWithString:url]]; 
//... 
// Pack in the user credentials 
[request setValue:[NSString stringWithFormat:@"Basic %@",authValue] forHTTPHeaderField:@"Authorization"]; 

// Send the asynchronous request as usual 
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *responseCode, NSData *responseData, NSError *error) { 

    // Do stuff.. 

} 
+0

Xin lưu ý mã này cung cấp cho bạn một cảnh báo ngay bây giờ "không được chấp nhận trong iOS 9'. Xem bài đăng này để khắc phục: http://stackoverflow.com/questions/30935304/sendasynchronousrequest-was-deprecated-in-ios -9-how-to-alter-code-to-fix – dan

1
NSURLConnection is deprecated in iOS 9, try this code which is from LazyTableImages example from here [https://developer.apple.com/library/ios/samplecode/LazyTableImages/Introduction/Intro.html][1] 
@property (nonatomic, strong) NSURLSessionDataTask *sessionTask; 



    //somwere in your code 

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] 
            initWithURL:[NSURL URLWithString:self.postLink] ]; 

    [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; 
    [request setHTTPShouldHandleCookies:NO]; 
    [request setTimeoutInterval:60]; 
    [request setHTTPMethod:@"POST"]; 
    [request addValue:[[NSUserDefaults standardUserDefaults] objectForKey:@"token"] 
    forHTTPHeaderField:@"ACCESSTOKEN"]; 


    self.sessionTask = [[NSURLSession sharedSession] dataTaskWithRequest:request 
                  completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
    //do completion staff here 
    }];