Day 8465 饭否oAuth验证学习笔记

饭否的oAuth认证文档在这里:https://github.com/FanfouAPI/FanFouAPIDoc/wiki/Oauth

如果采用他人已经写好的库,则基本不存在什么问题,而如果认证过程是自己写,并且之前又没有多少网络应用的编程经验,只看这个文档可能会走不少弯路。

1.xAuth的基本认证流程

xAuth是oAuth的简化版本,主要用于客户端一类本地应用程序的验证,oAuth的原生认证过程可以参考RFC 5849号文档(英文)及新浪开放平台的oAuth介绍(中文),这里不再赘述,主要介绍饭否提供的xAuth接口的认证流程:

  1. 使用access_token接口,辅以x_auth系列参数提交客户端认证,换取可用的oauth_token和oauth_token_secret。
  2. 使用获得的oauth_token和oauth_token_secret,结合申请的应用oauth_consumer_key和oauth_consumer_secret对API进行认证调用。

2.oAuth基本知识

  1. Header中的参数
    关于排列:首先对参数进行字母顺序升序排序,参数名相同的,按参数值排序,然后将排序后的参数按顺序用西文逗号(,)连接起来,作为Header中Authorization段放在“OAuth ”(注意有一个空格)段后的内容。对于饭否的oAuth,须注意:xAuth调用时对realm以及参数值是否有引号不敏感,但通过oAuth进行身份验证调用其它API时,要注意一不能有realm参数,二是参数值不能有引号,如果疏忽了这些问题,服务器会返回Invalid Signature的hash-error结构体,按返回的内容调试即可。
  2. 签名
    签名是为了保证数据未经篡改。不同的站点可能支持不同的签名方式,饭否只支持HMAC-SHA1方式的签名。饭否的xAuth阶段签名不需要使用Key(理论上这样是不对的,以后可能会修改),而在通过oAuth认证调用API功能时,则需要使用Key,Key应为consumer_secret和oauth_token_secret的连接结果,用“&”连接,然后附加到Header中OAuth Authorization的参数中。
  3. Base String
    Base String是计算签名的基础,oAuth规范要求的Base String组合方式在下文有介绍。

3.oAuth过程中需要注意的问题

  1. 关于oAuth API的使用
    如果按照oAuth文档中的指示,仅对那些参数附在Header中进行提交,很可能永远也无法通过认证,为何?RFC5849中已有明确提示(第3.5.1条):必须制定Authorization的Scheme为OAuth(大小写不能错),那什么是Authorization Scheme?其实就是告诉服务器认证的类型,也就是说,提交的Header中,Authorization段必须符合以下格式:

    Authorization: OAuth //后面是oAuth的其它参数

    如果这一步忘记了,服务器只会一个劲的返回Invalid Consumer Key,容易使人在Consumer Key的代入值上百思不得其解,其实只是因为服务器不知道这是oAuth认证,从而根本没有去读后面的参数,等于未将Consumer Key传给服务器,自然就会报Invalid Consumer Key了。

  2. 关于Base String的生成
    Base String的基本格式如下,其中&不是为了好看,而是必须存在的连接符号:
    HTTP请求方法(GET或POST,必须为大写)&URL Encode后的目标URL&排序并用西文AND符号(&)连接,然后整体做URLEncode后的参数
    这里许多通不过验证的人主要的问题可能是URL Encode后的结果与服务器期望值不符,原因也很简单:可能是所用的编程语言生成的URL Encode结果不标准。RFC中规定的编码需要满足以下两个关键条件:

    1、所有编码文字(%xx)中,xx的字母必须为大写(例如:%AA可以通过,而%aa就不行)
    2、以下字符绝对不能被编码:数字、字母(大写和小写)、-(短横线,或称西文减号)、.(西文小数点)、_(西文下划线)、~(西文波浪号),而除此之外的所有字符必须参加编码。

    鉴于此,如果所用的语言生成的结果不符合以上两条,请自行编写函数进行编码工作。

    • 关于签名(oauth_signature)
      以下是饭否在API文档中提供的签名规则,请完全照做:
      1、所有OAuth请求中,所有oauth_(含xauth_)开头的参数都要参加签名。
      2、在GET请求中,QueryString的所有参数也要参与签名,如:

      GET http://api.fanfou.com/statuses/user_timeline.xml?id=fanfou&page=2&format=html

      则id=fanfou、page=2、format=html也要参加签名。

      3、在POST请求中,只有当Content-Type为application/x-www-form-urlencoded时,
      所有参数才都全部要参加签名,如(POST数据没有经过编码):

      POST http://api.fanfou.com/account/update_profile.xml(更新用户信息)
      数据:url=http://www.aoisnow.net&location=山东 济南&description=测试上传用户信息&name=霞羽&[email protected]

      则数据中的url、location、description、name、email都要参加签名,且Content-Type需指定。

      4、在POST请求中,除了application/x-www-form-urlencoded的Content-Type,其它POST请求的附加
      参数都不参与签名,包括Content-Type为multipart/form-data时也不需要。例如(数据没有编码):

      POST http://api.fanfou.com/photos/upload.xml
      数据:photo=(照片的二进制数据)&status=测试&source=test

      则数据中的photo、status、source都不参加签名

      5、对于POST请求,经实践证明Content-Type默认为application/x-www-form-urlencoded
      在HTTP协议规定中这是默认值,但在提交给饭否的POST请求中,Content-Type必须指定为此
      否则会出现提交参数正确的情况下返回响应代码为200的空响应,切记。

Comments

  1. 关于Base String的生成
    Base String的基本格式如下,其中&不是为了好看,而是必须存在的连接符号:
    HTTP请求方法(GET或POST,必须为大写)&URL Encode后的目标URL&排序并用西文逗号(,)连接,然后整体做URLEncode后的参数

    这里逗号是不是改为&了?

  2. 博主,看到你的回复真好。不知道有无时间再看看这个
    所以求教,本人刚开始学,在获取未授权的Request Token就卡住了。

    http://fanfou.com 请求用户名和密码。信息为: “password error”

    点取消后出现如下提示

    XML解析错误:未组织好
    位置:http://fanfou.com/oauth/request_token?oauth_consumer_key=3159c9aa1a54b8734d3da88ee60a60ef&oauth_nonce=2659776296&oauth_signature=cDjegef64pHFH9d+7zJsjM2d674=&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1329888148
    行:3,列:94:

    我的疑问,
    oauth_nonce=2659776296,是不是位数不够?要32位?
    这一步HMAC-SHA1加密时的secret后面要不要加&(还没拿到oauth_token_secret)

    这个是我的写法。。
    https://dl.dropbox.com/u/48168238/3.html

  3. 用您提供的链接时而可以成功获取Token,时而不行。
    Nonce在RFC中对长度没有限制,但必须在请求过程中唯一(The nonce value MUST be unique across all requests with the same timestamp, client credentials, and token combinations),所以应该不是这个的问题。
    出错的时候服务器的返回是/hash/error结构,其中有对Expected BaseString的说明,您可以参考返回对提交进行修正。

  4. 万分感谢,调试了一个晚上一直Invalid Consumer Key,加上Content-Type之后终于可以了,再次谢谢^_^

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

 剩余字数 ( Characters available )

Your comment will be available after auditing.
您的评论将在通过审核后显示。

Please DO NOT add any links in your comment, otherwise it would be identified as SPAM automatically and never be audited.
请不要在评论中插入任何链接,否则将被自动归类为垃圾评论,且永远不会被提交给博主进行复审。

*