开发者

Yet another Cocoa OAuth (for Twitter) issue [duplicate]

This question already has an answer here: Closed 11 years ago.

Possible Duplicate:

Can't get Twitter OAuth callback authentication to work in Cocoa application

I have an application that sends Twitter updates (tweets). The current version does OAuth authentication using the OOB process:

(1) Send request token request:

consumer = [[OAConsumer alloc] initWithKey: kOAuthConsumerKey secret:kOAuthConsumerSecret];     
OAMutable开发者_运维知识库URLRequest *request = [[[OAMutableURLRequest alloc] 
        initWithURL: [NSURL URLWithString:kOAuthTwitterRequestTokenURL]                                                                
        consumer: self.consumer
        token: nil realm: nil signatureProvider: nil] autorelease];

[request setHTTPMethod:@"POST"];

OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];    
[fetcher fetchDataWithRequest:request delegate:self didFinishSelector:@selector(setRequestToken:withData:) didFailSelector:@selector(failRequestToken:data:)];

(2) Then assemble the authentication URL and open a browser window:

NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
self.requestToken = [[[OAToken alloc] initWithHTTPResponseBody:dataString] autorelease];

NSString *urlString = [NSString stringWithFormat: @"%@?oauth_token=%@", kOAuthTwitterAuthorizeURL, self.requestToken.key];
NSURL *requestURL = [NSURL URLWithString: urlString];

[[NSWorkspace sharedWorkspace] openURL: requestURL];

(3) Pop up an Alert Window with a text field, and get the PIN number from the user, then:

self.requestToken.secret = [input stringValue];

OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:kOAuthTwitterAccessTokenURL] consumer: self.consumer token: self.requestToken realm: nil signatureProvider: nil];
[request setHTTPMethod:@"POST"];
OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];    
[fetcher fetchDataWithRequest:request delegate:self didFinishSelector:@selector(setAccessToken:withData:) didFailSelector:@selector(failAccessToken:data:)];

(4) Save the return credentials:

NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
accessToken = [[OAToken alloc] initWithHTTPResponseBody:dataString];
[accessToken storeInUserDefaultsWithServiceProviderName: kOAuthTwitterDefaultsDomain prefix: kOAuthTwitterDefaultsPrefix];

(Memory Management and error checking removed for brevity)

This all works fine, but I really hate the process of redirecting to a browser and then making the user copy and paste the PIN number. I wanted to stop using the OOB method and go to the callback method. That takes some finagling for a Desktop application. So I switched to using a WebView, and I do steps 1 and 2 the same, except 2 does this instead:

NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
self.requestToken = [[[OAToken alloc] initWithHTTPResponseBody:dataString] autorelease];

OAMutableURLRequest* requestURL = [[[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:kOAuthTwitterAuthorizeURL] consumer:nil token:self.requestToken realm:nil signatureProvider:nil] autorelease]; 
[requestURL setParameters:[NSArray arrayWithObject:[[[OARequestParameter alloc] initWithName:@"oauth_token" value: self.requestToken.key] autorelease]]];   

[[webview mainFrame] loadRequest: requestURL];
[NSApp beginSheet: webSheet modalForWindow: [NSApp mainWindow] modalDelegate:self didEndSelector: @selector(webSheetDidEnd:returnCode:contextInfo:) contextInfo:nil];

I use the WebView PolicyDelegate to look for the redirect (to my callback URL) after the user has authorized using the Twitter webpage:

- (void)webView: (WebView *)webView decidePolicyForNavigationAction: (NSDictionary *)actionInformation request: (NSURLRequest *)request frame: (WebFrame *)frame
            decisionListener: (id<WebPolicyDecisionListener>)listener 
{
    NSString *urlString = [[actionInformation objectForKey:@"WebActionOriginalURLKey"] absoluteString];

    if ([urlString rangeOfString:@"oauth_verifier"].location != NSNotFound)
    {       
         // parse out oauth_token and oauth_verifier from the URL
     }
    self.requestToken.secret = oauthVerifier;
    [listener ignore];
    [NSApp endSheet:webSheet returnCode: 0];

    OAMutableURLRequest *request = [[[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:kOAuthTwitterAccessTokenURL] consumer: self.consumer token: self.requestToken realm: nil signatureProvider: nil] autorelease];
    [request setHTTPMethod:@"POST"];
    OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];    
    [fetcher fetchDataWithRequest:request delegate:self didFinishSelector:@selector(setAccessToken:withData:) didFailSelector:@selector(failAccessToken:data:)];
}

As far as I can tell, this should authenticate exactly the same. The only difference, as far as Twitter is concerned, is that I'm using the oauth_verifier from the callback URL instead of the one presented to the user (and provided back to my application). But if this was a true server-to-server implementation, that's the value I'd be using anyway.

What actually happens is that this last step (getting the access token) fails with:

failAccessToken: 'Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x101b3e780 {NSErrorFailingURLStringKey=http://api.twitter.com/oauth/access_token, NSUnderlyingError=0x101bacf40 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)", NSErrorFailingURLKey=http://api.twitter.com/oauth/access_token}'

Any ideas on what's causing this authentication to fail?

joe


I finally gave up on the OAuthConsumer framework and switched to the Google GTMOAuth framework. That works fine.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜