NSURLConnection और iOS में बेसिक HTTP ऑथेंटिकेशन


85

मुझे GET HTTP requestबेसिक के साथ एक प्रारंभिक आह्वान करने की आवश्यकता है Authentication। यह पहली बार होगा जब सर्वर को अनुरोध भेजा गया है और मेरे पास पहले से ही ऐसा है, username & passwordइसलिए प्राधिकरण के लिए सर्वर से चुनौती की कोई आवश्यकता नहीं है।

पहला प्रश्न:

  1. क्या NSURLConnectionबेसिक ऑथेंट को करने के लिए समकालिक सेट करना होगा? इस पोस्ट पर दिए गए उत्तर के अनुसार , ऐसा लगता है कि यदि आप Async मार्ग का विकल्प चुनते हैं, तो आप Basic Auth नहीं कर सकते।

  2. किसी को भी किसी भी नमूना कोड के बारे में पता है GET requestजो चुनौती की प्रतिक्रिया की आवश्यकता के बिना बेसिक प्रामाणिक दिखाता है ? ऐप्पल का प्रलेखन एक उदाहरण दिखाता है लेकिन सर्वर द्वारा क्लाइंट को चुनौती अनुरोध जारी करने के बाद ही।

मैं एसडीके के नए नेटवर्किंग हिस्से की तरह हूं और मुझे यकीन नहीं है कि इस काम को करने के लिए मुझे किन अन्य वर्गों का उपयोग करना चाहिए। (मैं 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
मैंने वह हिस्सा नहीं लिखा, यह MGTwitterEngine का हिस्सा है, NSData में जोड़ी गई श्रेणी से। NSData + Base64.h / m यहाँ देखें: github.com/ctshryock/MGTwitterEngine
catby

7
[authData base64EncodedString]Base64- एन्कोडिंग ( ) के लिए NSData + Base64.h और .m फ़ाइल को मैट गैलाघर से अपने XCode-Project ( Mac और iPhone पर Base64 एन्कोडिंग विकल्प ) में जोड़ें।
एलिमेंट

3
NSASCIIStringEncoding गैर-usascii उपयोगकर्ता नाम या पासवर्ड को दूषित करेगी। इसके बजाय NSUTF8StringEncoding का उपयोग करें
Dirk de Kok

4
base64EncodingWithLineLength NSData पर वर्ष 2014 में मौजूद नहीं है। इसके बजाय base64Encoding का उपयोग करें।
बिकस्टर

11
@bickster base64Encodingको iOS 7.0 और OS X 10.9 के बाद से हटा दिया गया है। मैं [authData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]इसके बजाय का उपयोग करें । इसके अलावा उपलब्ध `NSDataBase64Encoding64CharacterLineLength` याNSDataBase64Encoding76CharacterLineLength
डिर्क

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 डाइजेस्ट प्रामाणिक जैसी अन्य चुनौतियों को संभाल लेगा। यह एक व्यापार है।
बेन्जादो

2
वैसे भी, यह करने का "सही तरीका" है। अन्य सभी तरीके एक शॉर्टकट है।
लागोस

1
बहुत बहुत धन्यवाद! @moosgummi
LE SANG

@dom मैंने इसका उपयोग किया है लेकिन किसी कारणवश didRecieveAuthenticationChallenge को कॉल नहीं किया जा रहा है और मुझे साइट से 403 एक्सेस अस्वीकृत संदेश वापस मिल रहा है। किसी को पता है कि क्या हो गया है?
डेक्लेन मैककेना

हां, यह करने का एकमात्र सही तरीका है। और यह केवल पहली बार 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 में बदलने के लिए आप जिस विधि का उपयोग कर रहे हैं, उसका आधार64 अब हटा दिया गया है: - (NSString *)base64Encoding NS_DEPRECATED(10_6, 10_9, 4_0, 7_0);इसके बजाय NSDataBase64Encoding श्रेणी का उपयोग करने के लिए बेहतर है।
बेन

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 (या शायद कुछ सर्वरों की तुलना में कुछ भी अधिक नहीं है) है। - जस्टिन गैल्ज़िक 29 दिसंबर '09 17:29 पर

यह 80 तक सीमित नहीं है, यह NSData + Base64.h / m में बेस बेस 64EncodingWithLineLength का एक विकल्प है, जहां आप अपने एन्कोडेड स्ट्रिंग को कई लाइनों में विभाजित कर सकते हैं, जो अन्य एप्लिकेशन के लिए उपयोगी है, जैसे nntp ट्रांसमिशन। मेरा मानना ​​है कि ट्विटर इंजन लेखक द्वारा 80 को चुना जाता है ताकि अधिकांश उपयोगकर्ता / पासवर्ड एनकोडेड परिणाम को एक पंक्ति में समायोजित कर सकें।


0

आप AFNetworking का उपयोग कर सकते हैं (यह ओपनसोर्स है), यहां कोड है जो मेरे लिए काम करता है। यह कोड मूल प्रमाणीकरण के साथ फाइल भेजता है। बस यूआरएल, ईमेल और पासवर्ड बदलें।

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];
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.