由于工作需要,我最近接触了现在开放平台基本都会使用的OAuth协议。我相信OAuth是很强大的,但是,终于我还是切身的领教了中国互联网的的强大之处。
我的目的是制作一个iphone平台比较通用的OAuth库封装,通过简单的配置URL和key等参数,就可以快速的支持其开放平台,包括界面也是由我来完成。原先以为都是有开源封库的,只要简单的在做一层wrapper,开放几个接口应该就可以了。可惜的是想法是美好的,现实是残酷,道路也肯定是曲折的。
我看到的OAuth
说实话,我没有比较好的研究过OAuth这个协议,大致上来说,OAuth协议的目的是让第三方在不接触到用户的账号和密码情况下可以访问第一方的资源。这想起来真是太强大了。
OAUTH认证授权就三个步骤,三句话可以概括:
1. 获取未授权的Request Token
2. 获取用户授权的Request Token
3. 用授权的Request Token换取Access Token
当应用拿到Access Token后,就可以有权访问用户授权的资源了。大家肯能看出来了,这三个步骤不就是对应OAUTH的三个URL服务地址嘛。一点没错,上面的三个步骤中,每个步骤分别请求一个URL,并且收到相关信息,并且拿到上步的相关信息去请求接下来的URL直到拿到Access Token。
开源项目
很幸运,网络上开源项目有Objective-C版本的,我好不客气的checkout了,没有很深入的研究内部的代码,不过看到代码主要还是对数据结构的封装,对URLRequest的封装,还有一些加密的处理。小做修改,就可以将其中桌面版的移植到手机版本的。不过我马上发现新浪的代码也是使用OAuthConsumer这份代码。我毫不犹豫的投入到新浪的怀抱中。
新浪微博
l 新浪的判断机制
新浪微博被认为是行业翘楚,其代码和api应该不会差到哪。例子的程序跑的挺好,可是后来看到其中一段代码和注释,我真的凌乱了。
/*********************************************************************************************************
I am fully aware that this code is chock full 'o flunk. That said:
- first we check, using standard DOM-diving, for the pin, looking at both the old and new tags for it.
- if not found, we try a regex for it. This did not work for me (though it did work in test web pages).
- if STILL not found, we iterate the entire HTML and look for an all-numeric 'word', 7 characters in length
Ugly. I apologize for its inelegance. Bleah.
*********************************************************************************************************/
- (NSString *) locateAuthPinInWebView: (UIWebView *) webView {
NSString *pin;
NSString *html = [webView stringByEvaluatingJavaScriptFromString: @"document.body.innerText"];
NSLog(@"html:%@", [webView stringByEvaluatingJavaScriptFromString: @"document.body.innerHTML"]);
if (html.length == 0) return nil;
const char *rawHTML = (const char *) [html UTF8String];
int length = strlen(rawHTML), chunkLength = 0;
for (int i = 0; i < length; i++) {
if (rawHTML[i] < '0' || rawHTML[i] > '9') {
if (chunkLength == 6) {
char *buffer = (char *) malloc(chunkLength + 1);
memmove(buffer, &rawHTML[i - chunkLength], chunkLength);
buffer[chunkLength] = 0;
pin = [NSString stringWithUTF8String: buffer];
free(buffer);
return pin;
}
chunkLength = 0;
} else
chunkLength++;
}
return nil;
}
这段代码我也没细品,但是基本可以看出是在网页的html代码中找到一串数字,找到了就认为是授权pin码,我的天啊,算了,人家也道歉了。可是我真不知道怎么来做这个协议了。
后来才发现,其实只要取到verifier就可以了,这是直接在url里面就有,不用去html里面扣。
l 新浪支持的XAuth协议
什么是XAuth呢? 我没有去考据究竟XAuth是谁的创造, 它几乎搬了大部分OAuth的内容, 不过解决了一个什么问题呢? 解决了一个 "OAuth认证必须跳转到第一方去输入密码" 的问题(美其名曰提升用户体验)。我真不知道说什么了, 第三方是可以得到用户密码的, 那它是不是直接把OAuth的第一大feature给咔嚓掉了——那basic auth不能满足你么?
l OAuth提供两种认证方式
在新浪的文档中,我还注意到了这一段话:OAuth提供两种认证方式:query-string和http headers。我们推荐使用http header进行认证。
也许是这段话,腾讯微博做出了选择,让我悲剧了好长一段时间,终于向企鹅大哥妥协了。
腾讯微博
很快,调通了新浪微博后,我就开始腾讯的历程了。可是怎么都是不能授权成功,第一步获取token就失败了。后来我在FAQ中找到一段话:
请带上所有OAuth需要的参数,并按照规范传输(暂不支持Header方式传参,请通过GET,POST方式),腾讯微博授权协议在OAuth 【RFC 5849】 标准基础上开发。第一步需带上回调URL(oauth_callback参数),不是在第二步(非同于基他微博OAuth授权)。回调url需根据[RFC3986] 所定义的百分号机制进行URL转义。
我真的怀疑腾讯为了和新浪不兼容才不支持header方式传参的。就因为这一条,我最后还是选择了腾讯的封装,而弃用了新浪的封装。
另一个问题是:在请求request_token时传递oauth_callback参数, 因为写测试没用到callback, 所以肯定库会帮我填上oob(out-of-bound), 不过让我很崩溃的是, 给我跳转到了一个这样一个地方:
https://open.t.qq.com/oauth_html/oob?oauth_token=xxxxx&oauth_verifier=xxxxxx
结果是NOT FOUND了。
然后我又看到了下一条说明:
桌面应用,手机应用,因为没有callback_url(oauth_callback参数),所以在第一步传CALLBACK时请用 oauth_callback=null代替,不然得不到 PIN码。“null”串不区分大小写。
还有腾讯的不同之处还有是拦截url中的oauth_verifier=xxxxxx的部分来继续操作。相比新浪的,也是靠谱一点,可是也就是因为这个,后面豆瓣和网易我都没能都支持。
搜狐微博
搜狐微博的支持似乎比较弱,但是中规中规中矩的,除了界面比较丑陋,没有针对手机适配,其他的很容易就走通了流程了。
网易微博
开始我尝试了网易微博的授权,没能成功。
首先我发现的明显的一个不按照标准的地方是authorization步骤, 它提供了两个接口, 一个是/oauth/authorize, 一个是/oauth/authenticate, 首先我先申明这两个单词我一直搞不清, 不过在网易给OAuth