How to make NSURLRequest to obtain a Twitter request token?

前端 未结 2 1699
走了就别回头了
走了就别回头了 2021-01-07 11:17

I am trying to obtain a request token from Twitter with this code:

NSMutableURLRequest *mURLRequest = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithS         


        
相关标签:
2条回答
  • 2021-01-07 11:40

    Multiple errors (not sure if the list is complete, this is what I found at first glance):

    • the HTTP method should be simply @"POST", not @"POST foo", @"POST or I will kill you" or anything else;
    • Similarly, @"OAuth oauth_callback=\"" should be @"oauth_callback=\"";
    • You're not including all necessary header fields, for example, oauth_consumer_key, oauth_signature, oauth_signature_method, oauth_nonce and oauth_timestamp;
    • This does not return JSON. It returns an URL-encoded response, something like the example in the official documentation.
    0 讨论(0)
  • 2021-01-07 11:47

    After two days of frustration and cursing Twitter, I finally managed to do this. Here is my implementation. The class which will be used to make the request is "BL_TwitterRequest". This is only for obtaining the twitter request token.

    BL_TwitterRequest.h:

    #import <Foundation/Foundation.h>
    
    @interface BL_Request : NSObject <NSURLConnectionDelegate>
    
    @property (nonatomic, strong) NSMutableData *webData;
    
    -(void) makeRequest;
    

    Add the following NSString category at the top of the implementation class (BL_TwitterRequest.m). This will be used to get the URL encoded version of NSString.

    @implementation NSString (NSString_Extended)
    
    - (NSString *)urlencode {
        NSMutableString *output = [NSMutableString string];
        const unsigned char *source = (const unsigned char *)[self UTF8String];
        int sourceLen = strlen((const char *)source);
        for (int i = 0; i < sourceLen; ++i) {
            const unsigned char thisChar = source[i];
            if (thisChar == ' '){
                [output appendString:@"+"];
            } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' ||
                       (thisChar >= 'a' && thisChar <= 'z') ||
                       (thisChar >= 'A' && thisChar <= 'Z') ||
                       (thisChar >= '0' && thisChar <= '9')) {
                [output appendFormat:@"%c", thisChar];
            } else {
                [output appendFormat:@"%%%02X", thisChar];
            }
        }
        return output;
    }
    
    @end
    

    Add the below function in "BL_TwitterRequest.m". It will be used to generate the oAuth nonce. The function basically generates a random string of a specified length.

    -(NSString*) generateRandomStringOfLength:(int)length {
    
        NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        NSMutableString *randomString = [NSMutableString stringWithCapacity: length];
        for (int i = 0; i < length; i++) {
            [randomString appendFormat: @"%C", [letters characterAtIndex: arc4random() % [letters length]]];
        }
    
        return randomString;
    }
    

    Include the Base64 library from here. All you have to do is drag the "Base64.h" and "Base64.m" files into your project. Add the following imports:

    #include <CommonCrypto/CommonDigest.h>
    #include <CommonCrypto/CommonHMAC.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #import "Base64.h"
    

    Add another function as specified below. This will be used to get the HMAC-SHA1 value.

    - (NSString *)hmacsha1:(NSString *)data secret:(NSString *)key {
    
        const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
        const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
    
        unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
    
        CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    
        NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
    
        NSString *hash = [HMAC base64EncodedString];
    
        return hash;
    }
    

    Now for the main function that will make the request.

    -(void) makeRequest {
    
        _webData = [[NSMutableData alloc]init]; // WILL BE USED BY NSURLConnection
    
        NSString *httpMethod = @"POST";
        NSString *baseURL = @"https://api.twitter.com/oauth/request_token";
        NSString *oauthConsumerKey = @"YOUR_CONSUMER_KEY";
        NSString *oauthConsumerSecret = @"YOUR_CONSUMER_SECRET";
        NSString *oauth_timestamp = [NSString stringWithFormat:@"%.f", [[NSDate date]timeIntervalSince1970]];
        NSString *oauthNonce = [self generateRandomStringOfLength:42];
        NSString *oauthSignatureMethod = @"HMAC-SHA1";
        NSString *oauthVersion = @"1.0";
        NSString *oauthCallback = @"YOUR_TWITTER_CALLBACK_URL"; 
    
        //1. PERCENT CODE EVERY KEY AND VALUE THAT WILL BE SIGNED AND
        //   APPEND KEY AND VALUE WITH = AND &
    
        NSMutableString *parameterString = [[NSMutableString alloc]initWithFormat:@""];
    
        [parameterString appendFormat:@"oauth_callback=%@", [oauthCallback urlencode]];
        [parameterString appendFormat:@"&oauth_consumer_key=%@", [oauthConsumerKey urlencode]];
        [parameterString appendFormat:@"&oauth_nonce=%@", [oauthNonce urlencode]];
        [parameterString appendFormat:@"&oauth_signature_method=%@", [oauthSignatureMethod urlencode]];
        [parameterString appendFormat:@"&oauth_timestamp=%@", [oauth_timestamp urlencode]];
        [parameterString appendFormat:@"&oauth_version=%@", [oauthVersion urlencode]];
    
        //2. CREATE SIGNATURE STRING WITH HTTP METHOD AND ENCODED BASE URL AND PARAMETER STRING
    
        NSString *signatureBaseString = [NSString stringWithFormat:@"%@&%@&%@", httpMethod, [baseURL urlencode], [parameterString urlencode]];
    
        //3. GET THE SIGNING KEY NOW FROM CONSUMER SECRET
    
        NSString *signingKey = [NSString stringWithFormat:@"%@&", [oauthConsumerSecret urlencode]];
    
        //4. GET THE OUTPUT OF THE HMAC ALOGRITHM
    
        NSString *oauthSignature = [self hmacsha1:signatureBaseString secret:signingKey];
    
        // TIME TO MAKE THE CALL NOW
    
        NSMutableString *urlString = [[NSMutableString alloc]initWithFormat:@""];
    
        [urlString appendFormat:@"%@", baseURL];
    
        // INITIALIZE AUTHORIZATION HEADER
    
        NSMutableString *authHeader = [[NSMutableString alloc]initWithFormat:@""];
    
        [authHeader appendFormat:@"OAuth "]; // MIND THE SPACE AFTER 'OAuth'
    
        [authHeader appendFormat:@"oauth_nonce=\"%@\",", [oauthNonce urlencode]];
        [authHeader appendFormat:@"oauth_callback=\"%@\",", [oauthCallback urlencode]];
        [authHeader appendFormat:@"oauth_signature_method=\"%@\",", [oauthSignatureMethod urlencode]];
        [authHeader appendFormat:@"oauth_timestamp=\"%@\",", [oauth_timestamp urlencode]];
        [authHeader appendFormat:@"oauth_consumer_key=\"%@\",", [oauthConsumerKey urlencode]];
        [authHeader appendFormat:@"oauth_signature=\"%@\",", [oauthSignature urlencode]];
        [authHeader appendFormat:@"oauth_version=\"%@\"", [oauthVersion urlencode]];
    
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:urlString]] ;
    
        [request setHTTPMethod:httpMethod];
    
        [request setValue:authHeader forHTTPHeaderField:@"Authorization"];
    
        NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
    
        [connection start];
    
    }
    

    Now just implement the NSURLConnection delegate methods to get the response.

    #pragma mark - Connection Delegate
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    
        [_webData appendData:data];
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    
        NSString *resultString = [[NSString alloc]initWithData:_webData encoding:NSUTF8StringEncoding];
    
        NSLog(@"RESULT STRING : %@", resultString);  
    }
    

    If everything goes well the 'resultString' will have the oauth_token and oauth_token_secret.

    To make the call just do the following:

     BL_TwitterRequest *twitterRequest = [[BL_TwitterRequest alloc]init];
     [twitterRequest makeRequest];
    

    Remember any missed spaces or commas can result in an error.

    0 讨论(0)
提交回复
热议问题