【问题标题】:How to make NSURLRequest to obtain a Twitter request token?如何使 NSURLRequest 获取 Twitter 请求令牌?
【发布时间】:2013-02-01 12:53:32
【问题描述】:

我正在尝试使用以下代码从 Twitter 获取请求令牌:

NSMutableURLRequest *mURLRequest = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:@"https://api.twitter.com/oauth/request_token"]];
mURLRequest.HTTPMethod = @"POST /oauth/request_token HTTP/1.1";
[mURLRequest setValue:@"User-Agent" forHTTPHeaderField:@"Coupled HTTP"];
[mURLRequest setValue:@"OAuth oauth_callback=\"http%3A%2F%2Fbytolution.com\"" forHTTPHeaderField:@"Authorization"];
[mURLRequest setValue:@"api.twitter.com" forHTTPHeaderField:@"Host"];
[mURLRequest setValue:@"Accept" forHTTPHeaderField:@"*/*"];

NSHTTPURLResponse *urlResponse;
NSError *error;
NSError *serializationError;
NSData *responseData = [NSURLConnection sendSynchronousRequest:mURLRequest returningResponse:&urlResponse error:&error];
NSLog(@"data: %@, response:%@, error: %@", [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&serializationError], urlResponse.allHeaderFields, error);

但我得到的只是:

data: (null), response:{ Connection = close; "Content-Length" = 0; }, error: (null)

Here 是 Twitter 针对该主题的文档。

感谢您的帮助!

【问题讨论】:

    标签: objective-c http twitter nsurlrequest


    【解决方案1】:

    多处错误(不确定列表是否完整,这是我第一眼发现的):

    • HTTP 方法应该是简单的@"POST",而不是@"POST foo"@"POST or I will kill you" 或其他任何东西;
    • 同样,@"OAuth oauth_callback=\"" 应该是@"oauth_callback=\""
    • 您没有包含所有必要的标头字段,例如,oauth_consumer_keyoauth_signatureoauth_signature_methodoauth_nonceoauth_timestamp
    • 这不会返回 JSON。它返回一个 URL 编码的响应,类似于 official documentation 中的示例。

    【讨论】:

    • "要启动登录流程,您的应用程序必须通过向 POST oauth/request_token 发送 SIGNED 消息来获取请求令牌。此请求中唯一的唯一参数是 oauth_callback,它必须是 URL-您希望用户在完成第 2 步时重定向到的 URL 的编码版本。其余参数由 OAuth 签名过程添加。那么我是否需要oauth_signature 等?
    • This doc 声明你需要你的消费者密钥(没问题)和一个令牌(我正在尝试获取这个东西,我还没有)来创建一个 签署签名。我究竟做错了什么?顺便说一句,感谢您迄今为止的帮助!
    • @Dario 您基本上没有添加 任何 必需参数。
    • 我知道,但我不知道如何提供它们(oauth_callback 除外)
    • @Dario 为什么不使用 OAuth 库?正确实施 OAuth 非常困难。
    【解决方案2】:

    经过两天的挫折和诅咒 Twitter,我终于设法做到了。这是我的实现。用于发出请求的类是“BL_TwitterRequest”。这仅用于获取 twitter 请求令牌。

    BL_TwitterRequest.h:

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

    在实现类 (BL_TwitterRequest.m) 的顶部添加以下 NSString 类别。这将用于获取 NSString 的 URL 编码版本。

    @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
    

    在“BL_TwitterRequest.m”中添加以下函数。它将用于生成 oAuth 随机数。该函数基本上生成一个指定长度的随机字符串。

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

    包含来自here 的 Base64 库。您所要做的就是将“Base64.h”和“Base64.m”文件拖到您的项目中。添加以下导入:

    #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"
    

    添加如下指定的另一个函数。这将用于获取 HMAC-SHA1 值。

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

    现在是发出请求的主函数。

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

    现在只需实现 NSURLConnection 委托方法来获取响应。

    #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);  
    }
    

    如果一切顺利,“resultString”将包含 oauth_token 和 oauth_token_secret。

    要拨打电话,只需执行以下操作:

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

    请记住,任何遗漏的空格或逗号都可能导致错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-17
      • 1970-01-01
      • 2012-06-22
      • 1970-01-01
      相关资源
      最近更新 更多