Twitter 将于本月16日开始限制 Basic authentication 的使用,而直至本月31日,所有 Basic authentication 的请求都将只能收到 403 的回复了。尽管这会给亚洲某个地区的用户带来很大的不便,但是我们也要看到 OAuth 的好处,比如更强的安全性,因为不会泄漏用户的密码等信息,脱离密码的另一个好处就是各种应用可以无视用户对密码的修改,用户修改密码后并不会影响应用的正常工作,此外,我们可以给自己的消息设置一个自定义来源名称,利于个性化...
这两天我尽力地先改进自己的微博客同步工具,以便支持 OAuth 认证,失败了无数次,积累了一些经验,分享一下。
Authenticating Requests with OAuth 这篇官方的指导是必须要看的,事实上如果仔细地阅读了这篇文章,那么也不会出现什么问题了。不过我再画蛇添足地说一下具体的过程吧-.-
一、创建应用
当我们在 Twitter applications 页面创建了一个应用之后(假设为客户端的,以下也以此为例了),我们可以获得如下的信息:Consumer key ,Consumer secret ,Request token URL ,Access token URL ,Authorize URL 这些东西拿来干什么的,怎么用呢?我们继续...
二、获取未授权的 Request Token
当然不是一笔带过地说一句“把Consumer key 和 Consumer secret 放入 HTTP 请求中发送到 Twitter API ”就完了,我不知道有多少人看到这样一句话的时候是跟我一样的完全摸不着头脑,放入请求是要怎么个放法...?
在获取 Request Token 的时候,我们需要
oauth_consumer_key, 就是我们在创建应用时的 Consumer key
oauth_signature_method,Twitter 支持 HMAC-SHA1
oauth_timestamp,就是当前时间距 1970 00:00:00 GMT 的秒数,注意必须为整数值
oauth_nonce,每次自己随机生成的字符串,能保证每次的都不同就好了
oauth_version,现在为 1.0
oauth_callback,使用客户端的时候可以空着 oauth_callback,twitter能懂的~
oauth_signature,这个是最复杂的,下一段解释-.-
在获取 oauth_signature 之前我们要先得到一个叫做 base string 的东西,它由 HTTP 方法名(一般可以选择 GET 或者 POST,我说..我们这里用 GET)、URL 编码的请求路径(urlencode之后的 Request token URL)和请求的参数表(除了 oauth_signature 之外的所有参数按照名称经过重新排序之后使用&号连接,最后 urlencode)组成。这样我们就可以得到一个类似这样的 base string 了
GET&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonce%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26oauth_version%3D1.0
得到 base string 之后我们还需要一个 签名 key ,它就是由我们在创建程序时获得的 Consumer secret 和 oauth_token_secret 用 & 连接而成,不过我们在请求 Request Token 的时候还没有 oauth_token_secret 呀,那就 oauth_token_secret 为空,不过中间的 & 不能省。
在获得 base string 和 signing key 之后就可以利用这两者来生成 oauth_signature了,比如python的实现
base64.b64encode(hmac.new(consumer_secret+'&', base_string, hashlib.sha1).digest())
注意:在使用 GET 方式传送时,oauth_signature 不需要再进行 urlencode 了,但是在使用 POST 方式,将所有参数放在 header 里的时候,oauth_signature 还需要再进行一次 urlencode 。
好了,现在我们获取未授权 Request Token 时需要的参数都齐备了,连接到创建程序时获得的 Request token URL 之后(中间加?),得到类似这样一个地址
https://api.twitter.com/oauth/request_token?oauth_nonce=5151577474&oauth_timestamp=1281769547&oauth_consumer_key=your_consumer_key&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature=vdmXR5%2BZg5WHgFrC25vTZm4TfRg%3D
那么现在就用 GET 方式请求这个地址吧,返回的结果类似
oauth_token=xxxxx&oauth_token_secret=xxxxx&oauth_callback_confirmed=true
很轻松地就可以提取出来 request_token 和 request_token_secret 吧,不过此时的 Request Token 还是未授权的
三、用户授权此 Request Token
需要用户用浏览器打开这样一个地址:https://api.twitter.com/oauth/authorize?oauth_token=xxxxx ,当然其实最好是程序自动地帮用户打开了..-.-,很显然,前面一段呢就是用户在创建程序时获得的 Authorize URL ,中间加上 ?后面则是跟的上一步中获取到的 request_token ,好了,现在如果用户已经登陆了 twitter 的话,就可以看到这样一个界面了
点击 Allow 后完成授权,此时会出现一串 PIN 码,用户应该记下来,以便接下来再获取 Access token
四、获取 Access token
总结一下,我们通过以上几步新获得了几个参数,授权过的 request_token 和 request_token_secret,还有一个 PIN 码。
获取 Access token 的过程和获取未授权的 Request token 过程是类似的,所以我这里只介绍一下其中仅有的几点区别,获取 Access token 时和 Request token不同的是需要 8 个参数,去掉 oauth_callback 这个,但是另外加上 oauth_verifier (值就是上面的 PIN 码)和 oauth_token (值就是刚获得的 request_token),另外 signing key 里的 oauth_token_secret 不再为空了,它就是刚才获得的 request_token_secret ,最后一点就是请求的地址前面部分为创建程序时获得的 Access token URL ,其他的规则都是一样的,当然最后获得的放回结果里就是 access_token 和 access_token_secret 了,对于 access_token 和 access_token_secret 我们可以保存下来,以后访问受保护的资源则直接利用它,而不需要每一次都经历一下上面的曲折阶段。
五、拿到 Access token 来发一条消息
和获取 Access token 相比,进行资源访问等操作时所需的参数不包含 oauth_verifier,而外添加一个 status 的参数(准确点应该是 POST 内容的主体部分),其值为发送的消息(UTF-8编码不解释) 其他参数则都是一样的( oauth_token 为 access_token),oauth_signature 的生成当然也还是一样需要 signing key (由 consumer_key 和 access_token_secret组成)和 base string (请求地址为 API 地址),不过这一次必须要使用 POST 方式提交数据,所以在生成 base string 时的方法为 POST,最终生成的 oauth_signature 也需要 urlencode。
这一次,所有的参数不再需要跟某个地址进行连接操作了,我们构造一个 HTTP Authorization header ,结果如下
OAuth status="%E4%B8%80%E5%A0%86%E5%BE%AE%E5%8D%9A%E5%AE%A2",oauth_nonce="4992019565",oauth_timestamp="1281772029",oauth_consumer_key="your_consumer_key",oauth_signature_method="HMAC-SHA1",oauth_version="1.0",oauth_token="your_access_token",oauth_signature="dFmXo%2BxOWFMOhkZWTl80fh3IelM%3D"
可见就是"OAuth "之后将所有的参数列了出来,这样在使用 POST 方式请求 API 的时候带上这样一个 Authorization header ,同时 POST 的内容为 status=message (不要忘记 urlencode),便能成功地发布一条消息了。