iOS의 NSURLConnection 및 기본 HTTP 인증


85

GET HTTP requestBasic 으로 이니셜을 호출해야합니다 Authentication. 요청이 서버로 처음 전송되고 이미 username & password서버에서 인증을 요청할 필요가 없습니다.

첫 번째 질문 :

  1. 않습니다 NSURLConnection기본 인증을 수행하는 동기로 설정되어야한다? 이 게시물 의 답변에 따르면 비동기 경로를 선택하면 기본 인증을 할 수없는 것 같습니다.

  2. 누구든지 GET request챌린지 응답없이 기본 인증을 설명하는 샘플 코드를 알고 있습니까? Apple의 문서 에 예제가 나와 있지만 서버가 클라이언트에 챌린지 요청을 보낸 후에 만 ​​해당됩니다.

저는 SDK의 네트워킹 부분이 새로워졌고이 작업을 수행하는 데 사용해야하는 다른 클래스를 잘 모르겠습니다. ( NSURLCredential클래스가 보이지만 NSURLAuthenticationChallenge클라이언트가 서버에서 인증 된 리소스를 요청한 후에 만 사용되는 것 같습니다 .)

답변:


132

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

이 방법이 챌린지 루프를 거쳐야한다고 생각하지는 않지만 틀릴 수 있습니다.


2
나는 그 부분을 작성하지 않았으며 NSData에 추가 된 카테고리에서 MGTwitterEngine의 일부일뿐입니다. 여기에서 NSData + Base64.h / m을 참조하십시오 : github.com/ctshryock/MGTwitterEngine
catsby dec

7
base64 인코딩 ( [authData base64EncodedString])의 경우 Matt Gallagher의 NSData + Base64.h 및 .m 파일을 XCode-Project ( Mac 및 iPhone의 Base64 인코딩 옵션)에 추가합니다 .
elim

3
NSASCIIStringEncoding은 비 usascii 사용자 이름 또는 암호를 손상시킵니다. 대신 NSUTF8StringEncoding 사용
Dirk de Kok

4
base64EncodingWithLineLength는 NSData에서 2014 년에 존재하지 않습니다. 대신 base64Encoding을 사용하십시오.
bickster 2014-08-13

11
@bickster base64Encoding는 iOS 7.0 및 OS X 10.9부터 더 이상 사용되지 않습니다. [authData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]대신 사용 합니다. `NSDataBase64Encoding64CharacterLineLength` 또는NSDataBase64Encoding76CharacterLineLength
Dirk

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

9
이것은 다른 솔루션과 완전히 동일하지 않습니다. 먼저 서버에 연결하고 401 응답을 수신 한 다음 올바른 자격 증명으로 응답합니다. 그래서 당신은 왕복을 낭비하고 있습니다. 장점은 코드가 HTTP Digest Auth와 같은 다른 문제를 처리한다는 것입니다. 트레이드 오프입니다.
benzado 2012

2
어쨌든 이것이 "올바른 방법"입니다. 다른 모든 방법은 지름길입니다.
lagos

1
정말 고마워! @moosgummi
LE는 SANG

@dom 나는 이것을 사용했지만 어떤 이유로 didRecieveAuthenticationChallenge가 호출되지 않고 사이트에서 403 액세스 거부 메시지를 받고 있습니다. 아무도 잘못 된 것이 무엇인지 알고 있습니까?
Declan McKenna

예, 이것이 유일한 올바른 방법입니다. 그리고 처음에는 401 응답 만 발생합니다. 동일한 서버에 대한 후속 요청은 인증과 함께 전송됩니다.
dgatwood

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

이에 대한 귀하의 의견을 알려주십시오.

감사


NSData를 NSString으로 변환하는 데 사용하는 base64Encoding 메서드는 이제 더 이상 사용되지 않습니다. - (NSString *)base64Encoding NS_DEPRECATED(10_6, 10_9, 4_0, 7_0);대신 NSDataBase64Encoding 범주를 사용하는 것이 좋습니다.
Ben

7

MGTwitterEngine 전체를 가져오고 싶지 않고 비동기 요청을하지 않는 경우 다음을 사용할 수 있습니다. 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

3

NSData :: dataUsingEncoding은 더 이상 사용되지 않으므로 (ios 7.0) 다음 솔루션을 사용할 수 있습니다.

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

1

연결에 GTMHTTPFetcher 를 사용 하는 경우 기본 인증도 매우 쉽습니다. 가져 오기를 시작하기 전에 가져 오기 프로그램에게 자격 증명을 제공하기 만하면됩니다.

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

0

예제 코드에서 인코딩 줄 길이를 80으로 제한하는 이유가 무엇인지 말해 줄 수 있습니까? 나는 HTTP 헤더의 최대 길이가 4k와 같다고 생각했습니다 (또는 일부 서버는 그보다 더 오래 걸리지 않을 수도 있습니다). – Justin Galzic 2009 년 12 월 29 일 17:29

80으로 제한되지 않고 NSData + Base64.h / m의 base64EncodingWithLineLength 메소드의 옵션으로 인코딩 된 문자열을 여러 줄로 분할 할 수 있으며 nntp 전송과 같은 다른 애플리케이션에 유용합니다. 나는 트위터 엔진 작성자가 80을 선택하여 대부분의 사용자 / 비밀번호로 인코딩 된 결과를 한 줄에 수용 할 수있는 길이라고 생각합니다.


0

AFNetworking (오픈 소스)을 사용할 수 있습니다 . 여기 저에게 도움이되는 코드가 있습니다. 이 코드는 기본 인증으로 파일을 보냅니다. URL, 이메일 및 비밀번호를 변경하십시오.

NSString *serverUrl = [NSString stringWithFormat:@"http://www.yoursite.com/uploadlink", profile.host];
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:serverUrl parameters:nil error:nil];


NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

// Forming string with credentials 'myusername:mypassword'
NSString *authStr = [NSString stringWithFormat:@"%@:%@", email, emailPassword];
// 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"];

manager.responseSerializer = [AFHTTPResponseSerializer serializer];

NSURL *filePath = [NSURL fileURLWithPath:[url path]];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:^(NSProgress * _Nonnull uploadProgress) {
// This is not called back on the main queue.
// You are responsible for dispatching to the main queue for UI updates
     dispatch_async(dispatch_get_main_queue(), ^{
                //Update the progress view
                LLog(@"progres increase... %@ , fraction: %f", uploadProgress.debugDescription, uploadProgress.fractionCompleted);
            });
        } completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
            if (error) {
                NSLog(@"Error: %@", error);
            } else {
                NSLog(@"Success: %@ %@", response, responseObject);
            }
        }];
[uploadTask resume];
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.