OpenSocial and 2-legged OAuth 基本概念:
Two legs的意思是OAuth的参与者为两个:Social Network Server和App server.
2-legged OAuth协议是两个服务器backend的交互,与3-legged相比,缺少了user这个角色,不需要经过user-agent(Gadget,浏览器等)。
因为不需要user,所以自然不需要用户认证。这就要求用户事先已经允许App Server访问存放于Social Site的私人数据。
因为我还没能跑出实际例子,所以自己直观的感觉较少,主要是通过阅读一些文章了解。
以下主要是翻译自一篇介绍2-legged的文章,其中也加了不少自己的补充:
原文地址:http://sites.google.com/site/oauthgoog/2leggedoauth/2opensocialrestapi&ei=ISHpS8ijB4qOkQX-xoSICw&usg=AFQjCNH_6WhDOc9Vbgx7k1p3DsDk5F17ug&sig2=3-QKOl13GUAHFnTHEWKe0g (需over the wall)
OpenSocial的REST API是通过OAuth协议实现授权机制:
简单描述一下就是,OpenSocial中定义了REST API,通过call这些API可以访问私人数据,当取涉及隐私的数据时,需要对的app进行授权,而OAuth是基于API的授权协议,显然再合适不过。但是对于一些公共数据,则不需要授权。
OAuth在OpenSocial中有两种形式,2-legged 和 3legged。
本文将解释这两种形式不同的应用场景,以及为何对于大多数OpenSocial container(比如Igoogle等能放置gadget的容器),2-legged OAuth变得更加重要并首先被支持。
首先学习一下OpenSocial Restful API的Spec第四节:
http://www.opensocial.org/Technical-Resources/opensocial-spec-v08/restful-api-specification
大致意思就是每个RESTcall都拥有自己的请求上下文,一般情况下,这个上下文包含了授权和认证信息。比如包括了请求者的Id(在初始化request时产生),以及app ID(call Rest api的主动方的id)
Gadget容器必须是OAuth的Service Provider(SP)
Gadget容器必须也支持Consumer Request OAuth extension协议:http://oauth.googlecode.com/svn/spec/ext/consumer_request/1.0/drafts/1/spec.html,通过此协议,用户无需做身份认证操作(2-legged实现的基础)。Consumer Request OAuth extension协议实现的功能就是无需用户操作的在consumer和SP间通过OAuth的签名流程对request进行签名。
app使用前需要已经被用户授权,容器需要与app建立信任关系(其过程就是在容器中保存app的secret和key)。
容器还应该支持无需验证授权获取公共数据的接口。
2-legged 与 3-legged的区别及联系
OAuth一般是指3-legged OAuth,这点从OAuth协议就能看出,整个OAuth的过程需要用户的这个角色,用户需要登录(身份认证)和允许APP访问数据(授权操作)。因此3 legged OAuth是OAuth的标准版本,并已被Yahoo Google Aol等部署应用,3-legged需要用户的参与,从OAuth consmer开始,重定向到OAuth provider,去做登录及授权,如果授权通过,用户又被弹回OAuth consumer,因此用户这一些列操作被戏称为“dance”。而这支非常灵动的舞蹈,让整个网络的app和数据互动起来了,但是代价却是让用户头晕的一些列操作,用户体验是非常差的= =#(可以想想,一个并不了解OAuth流程的用户,对于两个site间来回跳并且要阅读很多类似法律条款的授权警告,以及操作,是多么的困惑)
之前我写过一篇介绍flicker作为sp,Ning作为Consumer的case study。
http://djb4ke.iteye.com/blog/664065
flicker增加用户体验的方式是只需授权一次,而后授权信息一直保留并可管理。
我还看过一些SNS网站做联系人导入的做法,也是为了增加用户体验,具体做法是:
要求用户提供第三方网站的用户名和密码!!
比如renren,人人还在下面有个注释“人人网不会记录你的密码,请放心使用”
不做太多评论,只想说一句“如果每个服务商都承诺对用户的用户名密码完全无视,还要OAuth干啥?”
至于renren取联系人是通过OAuth,app验证通过后取联系人信息,还是renren拿着用户名密码到你邮箱里扫视一遍,顺便拿个联系人信息,就不得而知了。
(警告:互联网由于技术不断发展确实是变得越来越安全,但是同时,在我们不断信任各种服务商的同时,警惕性决不能下降,试想一下跑到一个陌生的站点,很可能是个山寨站点,同样要求你提供你的邮箱密码,同样承诺无视你的密码,后果会如何= =)
2-legged OAuth是标准OAuth的变种形式,不需要前面提到的“dance”,即不需要用户参与。
2-legged OAuth又被称作Signed Fetch or Phone Home,尤其在OpenSocial社区
Signed Fetch比较好理解,就是获取数据的操作是签过名的,这里签名是指参照OAuth签名流程的签名,签完名自然就代表此请求是加上identity了。
如今,广泛使用中的大部分REST API调用是通过2-legged OAuth方式,并不是标准版的OAuth-3 legged。原因是通过2-legged,Gadget可以与Gadget的home server建立connection。
home server是指存放Gadget xml的server,开发者开发完gadget后会将gadget的xml源码放置于一个server,这与gadget在容器中运行时存在于容器中不是一个概念。
Signed Fetch允许gadget直接与自己的home server联系(类似直接打电话回家,因此叫phone home)。
此时,不需要“dance”的原因是,home server预先并不存在关于此用户的数据。因此也就不需要授权访问并不存在的数据。
OpenSocial REST API应用实例
OpenSocial容器开发REST API的两种主要应用实例
①为了获得gadget某使用者的用户信息, Gadget的home server向container发起server端到server端的的REST call。
举例:查询该用户的新朋友列表,这是Reverse Phone Home的应用(Phone Home:gadget to home server;Reverse Phone Home:home server get gadget user information)
②第三方的站点(没有gadget)想获得用户的允许以访问用户在social network上的私人数据。
举例:下载该用户的朋友列表。
第②个应用场景必须通过3-legged OAuth,
然而,第①个应用场景才是很多OpenSocial容器非常紧迫开放REST API的原因。
虽然在理论上,通过3-legged OAuth支持Reverse Phone Home是可行的,但是实际上使用3-legged是多余的并且将用户体验完全复杂化(试想一下call每个不同的REST API都需要用户点approve授权会是多可怕的一件事= =),在下面的章节中我们将解释为何这样说。
下面这张图是应用实例的数据流图
Reverse Phone Home
当用户在自己的页面添加一个gadget,在gadget会出现一些选项来控制gadget的访问级别,比如是否可以访问联系人列表,活动等。
也可以通过UI来设置gadget的home server对用户数据的访问权限
container可以对权限设置有默认选择,设置gadget的访问权限与home server相同。
如果用户在之后通过UI改变了这些权限设置,或者从自己的页面删除了gadget,home server会相应的做出改变。
这种两种设置相结合的做法,使得用户无需通过“dance”进行home server的访问权限设置。
更重要的是,提供了一种一致性的做法去修改或删除这些权限。因为对于用户来说。所有操作都在gadget中进行。Gadget外部不存在一个标准的如OAuth 3-legged那样的UI流程,通过专用的权限管理页面来管理权限设置。
这种一致性带来的好处显而易见,比如,如果用户在自己的页面上删除的gadget,但是忘记到权限管理界面删除home server对于用户数据的访问权限。
现在我们避免了OAuth dance,gadget的home server可以通过REST API访问OpenSocial容器中的用户数据。然而,这产生了两个安全和认证相关的问题
①container如何验证请求确实是从gadget的home server发过来?
②home server如何确认他得到的用户数据是他想要的?
对于第①个问题:OpenSocial container需要共享secret给gadget的开发者。从而,home server可以使用这个secret来对请求签名,也就表明了自己的身份。
一种做法是container的开发站点提供一个gadget的注册网站,开发人员登录后,输入自己gadget URL,随后container显示出一段代码,然后开发人员将这段代码添加至他们的gadget spec。随后container会检查gadget是否包含那段代码,如果找到,则验证了gadget确实是此开发人员所拥有。通过验证后,container会提供gadget的开发者一对OAuth Consumer Key& Secret。于是开发者可以将这对Key保存到home server上。
一个比较好的例子,MySpace's OpenSocial registration process.
注意:前面我们还提到Phone Home,即gadget通过container call home server,与上面的例子的方向相反,这些从container发出request也同样需要数字签名,container可以选择共享的secret做数字签名。
对于第②个问题是验证用户,幸运的是,在container和gadget的home server已经存在一个公共的用户识别符,当gadget对home server发起“phone call”,container会在请求中加上owner和viewer的id。因此home server能够本地保存用户id。如果home server想取该用户的更多数据,发起带上用户id参数的请求即可。
OpenSocial App Data
2-legged OAuth的另一个优势是,当OpenSocial container收到一个REST call,可以很方便的将发起这个call的服务器与gadget关联起来。如果home server请求访问OpenSocial的App Data,container需要知道返回哪个gadget的appdata,有了这个关联,就变得容易多了。此外,如果home server想增加信息到用户的活动,或者发送信息到用户,container可以将更新的信息传递至gadget。
phone home 和 reverse phone home的参数对比:
OAuth 参数 | Phone Home | Reverse Phone Home |
oauth_consumer_key | Container Name:例 orkut.com | opensocial_appid from phone home request |
oauth_signature | gadget specific shared secret | gadget specific shared secret |
opensocial_appid | gadget ID assigned by container | N/A |
opensocial_ownerid | user ID assigned by container | N/A |
opensocial_viewerid | user ID assigned by container | N/A |
xoauth_requestor_id | N/A | opensocial_ownerid from phone home request |
注意:
oauth_signature在两种case可以使用相同的共享secret。(有些container倾向于通过非对称密钥的方式签名phone home requests)
container可以指定用于reverse phone home calls的oauth_consumer_key,但是简单的方式是container发起phone home calls使用与之(oauth_consumer_key)相同的appid。
同时支持 3 legged & 2 legged
3 legged & 2 legged可以使用相同的API endpoint,只需要通过判断是否有OAuth token传递过来。
在3-legged OAuth中,OAuth token将传递过来,所请求的用户数据的ID可以从token中得到,但是发起REST CALL的server身份仍然需要再验证签名后从oauth_consumer_key得到。