本文的pdf版本下载地址
本文是对以下两篇文章的整理
系列博文地址 http://blog.csdn.net/hereweare2009/article/details/3968582
参考翻译文档 http://www.rollingcode.org/blog/f/oauth-core-1.0-final-cn.html
摘要:OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAUTH的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAUTH是安全的。同时,任何第三方都可以使用OAUTH认证服务,任何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间,因而OAUTH是简易的。
目前互联网很多服务如Open API,很多大头公司如Google,Yahoo,Microsoft等都提供了OAUTH认证服务,这些都足以说明OAUTH标准逐渐成为开放资源授权的标准。
典型案例:如果一个用户拥有两项服务:一项服务是图片在线存储服务A,另一个是图片在线打印服务B。如下图所示。由于服务A与服务B是由两家不同的服务提供商提供的,所以用户在这两家服务提供商的网站上各自注册了两个用户,假设这两个用户名各不相同,密码也各不相同。当用户要使用服务B打印存储在服务A上的图片时,用户该如何处理?法一:用户可能先将待打印的图片从服务A上下载下来并上传到服务B上打印,这种方式安全但处理比较繁琐,效率低下;法二:用户将在服务A上注册的用户名与密码提供给服务B,服务B使用用户的帐号再去服务A处下载待打印的图片,这种方式效率是提高了,但是安全性大大降低了,服务B可以使用用户的用户名与密码去服务A上查看甚至篡改用户的资源。
很多公司和个人都尝试解决这类问题,包括Google、Yahoo、Microsoft,这也促使OAUTH项目组的产生。OAuth是由Blaine Cook、Chris Messina、Larry Halff 及David Recordon共同发起的,目的在于为API访问授权提供一个开放的标准。OAuth规范的1.0版于2007年12月4日发布。通过官方网址:http://oauth.net可以阅读更多的相关信息。
在官方网站的首页,可以看到下面这段简介:
An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.
大概意思是说OAUTH是一种开放的协议,为桌面程序或者基于BS的web应用提供了一种简单的,标准的方式去访问需要用户授权的API服务。OAUTH类似于Flickr Auth、Google's AuthSub、Yahoo's BBAuth、 Facebook Auth等。OAUTH认证授权具有以下特点:
1. 简单:不管是OAUTH服务提供者还是应用开发者,都很容易于理解与使用;
2. 安全:没有涉及到用户密钥等信息,更安全更灵活;
3. 开放:任何服务提供商都可以实现OAUTH,任何软件开发商都可以使用OAUTH;
在弄清楚OAUTH流程之前,我们先了解下OAUTH的一些术语的定义:
服务提供方 Service Provider:一个允许通过OAuth访问的web应用程序。
用户 User:在服务提供方处拥有帐号的个人。
消费方 Consumer:一个代表用户以OAuth形式访问服务提供方的网站或应用程序。
受保护资源 Protected Resource(s):服务提供方所掌控的数据,能被通过用户认证的消费方访问。
消费方开发者 Consumer Developer:实现消费方的个人或组织。
消费方键值 Consumer Key: 消费方用来向服务提供方标示身份的值。
消费方密钥 Consumer Secret:消费方用于建立对消费方键值所有权的密钥。
请求令牌 Request Token:消费方用于从用户处获得授权并换取请求令牌的值。
访问令牌 Access Token:消费方用于代表用户在没有密码的情况下访问受保护资源的值。
令牌密钥 Token Secret:消费方用于建立对特定令牌所有权的密钥。
OAuth协议参数 OAuth Protocol Parameters:参数名称,以oauth_开头。
服务提供方负责为消费方开发者创建消费方键值和消费方密钥,所需条件和过程由服务提供方决定。
服务提供方文档包括:
消费方所使用的请求URL (请求URL)、访问请求令牌URL和访问令牌URL所使用的HTTP方法;
服务提供方支持的签名方法;
获取令牌所需的其他附加请求参数,不得以oauth_开头。
消费方开发者必须在服务提供者处创建一组消费方键值和消费方密钥。注册时开发者可能会被服务提供方要求提供某些附加信息。
服务提供方以一组消费方键值和消费方密钥来鉴定消费方(正如用登录名和密码来鉴定用户)。 这种识别方式使得服务提供方可以向消费方开放不同的访问级别。服务提供方不应依赖消费方密钥来验证消费方的身份,除非能确保消费方密钥不被第三方获知。消费方密钥可以是一个空串,例如消费方无需验证或使用RSA等其他方式验证。
请求令牌URL(Request Token URL): 获取未授权的Request Token服务地址;
用户授权URL(User Authorization URL): 获取用户授权的Request Token服务地址;
访问令牌URL(Access Token URL): 用授权的Request Token换取Access Token的服务地址。
三种URL必须包含方案、授权和路径,可以包含[RFC3986]第三部分所定义的查询和片段,不得(MUST NOT)包含任何OAuth协议参数。例如下面的示例:
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
| _____________________|__
/ \ / \
urn:example:animal:ferret:nose
oauth_consumer_key: 消费方用来向服务提供方标示身份的ID。该参数值的获取一般是要去OAUTH服务提供商处注册一个应用,再获取该应用的oauth_consumer_key。如Yahoo该值的注册地址为:https://developer.yahoo.com/dashboard/
oauth_consumer_secret:oauth_consumer_key对应的密钥。
oauth_token:服务提供方返回令牌参数。最后一次返回的该参数就是访问令牌,有了这个访问令牌,服务B就可以大摇大摆去拥有资源的服务A抓取有权限抓取的资源了。
oauth_token_secret:oauth_token对应的私钥。
oauth_signature_method: 请求串的签名方法,应用每次向OAUTH三个服务地址发送请求时,必须对请求进行签名。签名的方法有:HMAC-SHA1、RSA-SHA1与PLAINTEXT等三种。
oauth_signature: 用上面的签名方法对请求签名生成的签名字符串。
oauth_timestamp: 发起请求的时间戳,请求时间戳用格林威治时间1970年1月1日0时0分0秒起的秒数表示,除非服务提供方另外指定。 请求时间戳必须是个正整数,并必须不小于上一个请求中的时间戳。
oauth_nonce: 消费方必须为一个时间戳的所有请求的生成不同的单次值。单次值是一个随机字符串,是为每次请求生成的唯一值。服务提供方用单次值验证一个请求之前从未被发起过,有助于防止非安全通道(例如HTTP)上的重放攻击。
oauth_version: OAUTH的版本号,可选,其值必须为1.0。
以上参数名称和值都是大小写敏感的。关于参数的更多规定详见
http://www.rollingcode.org/blog/f/oauth-core-1.0-final-cn.html
Unsupported parameter 参数错误
Unsupported signature method 签名方法错误
Missing required parameter 参数丢失
Duplicated OAuth Protocol Parameter 参数重复
Invalid Consumer Key 非法key
Invalid / expired Token 失效或者非法的token
Invalid signature 签名非法
Invalid / used nonce 非法的nonce
在弄清楚了OAUTH的术语后,我们可以对OAUTH认证授权的流程进行初步认识。其实,简单的来说,OAUTH认证授权就三个步骤,三句话可以概括:
1. 获取未授权的Request Token
2. 获取用户授权的Request Token
3. 用授权的Request Token换取Access Token
具体的流程下面按步骤说明
消费方向服务提供方的请求令牌URL发起一个HTTP请求,服务提供方的文档指定了可以使用的HTTP方法,推荐使用POST。 具体参数如下:
发起请求时,需要的参数由服务提供方文档提供,可以包含如下:
oauth_consumer_key:消费方键值。
oauth_signature_method:消费方签署本请求所用的签名方法。
oauth_signature:签名字符串。
oauth_timestamp:请求时间戳。
oauth_nonce:单次值。
oauth_version:可选。如果存在,其值必须为1.0。如果参数不存在,服务提供方必须假定协议版本为1.0。 服务提供方对1.0以外取值的响应尚未定义。
额外参数:由服务提供方定义的任意额外参数
示例:
Authorization: OAuth realm="http://sp.example.com/",
oauth_consumer_key="0685bd9184jfhq22",
oauth_signature_method="HMAC-SHA1",
oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D",
oauth_timestamp="137131200",
oauth_version="1.0"
响应包含如下参数:
oauth_token:请求令牌
oauth_token_secret:令牌密钥
附加参数:由服务提供方定义的任意参数。
示例:
oauth_token=ab3cd9j4ks73hf7g&oauth_token_secret=xyz4992k83j47x0b
获取用户授权之前,消费方不能使用访问令牌。
为了能够换取访问令牌,消费方必须引导用户到服务提供方处并获得用户的核准。为此,消费方构造一个指向服务提供方用户授权URL的HTTP GET请求,包含以下参数:
oauth_token:可选。在前述步骤中获得的请求令牌。服务提供方可以声明此参数为必须,也可以允许不包含在授权URL中并提示用户手工输入。
oauth_callback:可选。消费方可以指定一个URL,当获取用户授权成功后,服务提供方将重定向用户到这个URL。
附加参数:由服务提供方定义的任意参数。
消费方构造请求URL并通过用户的浏览器将用户重定向到该地址。如果消费方无法自动进行HTTP重定向,则须告知用户如何手工访问该地址。
注意:如果服务提供方已知消费方运行于移动设备或机顶盒, 则应保证用户授权URL和请求令牌适于手工输入。
服务提供方验证用户身份并询问用户是否许可。OAuth不指定服务提供方如何鉴定用户,但定义了以下必须的步骤:
服务提供方询问用户许可前,必须先验证用户身份,如用户未登录可以要求其先登录。
服务提供方向用户展示消费方访问请求相关的信息,包括访问时限、被访问资源等,也可以包含其他服务提供方指定的信息。
用户必须授权或否决服务提供方允许消费方代表用户访问受保护资源。一旦用户否决,服务提供方不得允许消费方访问受保护资源。
当服务提供方根据消费方键值显示关于消费方的信息时,必须向用户告知其是否能确保此信息的确实可靠,而所使用的方式不在本规范讨论范围之内。
用户通过服务提供方认证并对消费方授权后,消费方必须被告知请求令牌已被授权并可以交换访问令牌。如果用户否决的访问,则消费方可以被告知请求令牌已被回收。
如果消费方在oauth_callback中提供了回调URL,则服务提供方构造一个HTTP GET请求URL,重定向用户浏览器到该URL,并包含如下参数:
oauth_token:被用户授权或否决的请求令牌
回调URL可以包含消费方提供的查询参数,服务提供方必须保持已有查询不变并追加oauth_token参数。如果没有提供回调URL则服务提供方告知用户手工通知消费方授权完成。
请求令牌及其密钥必须被交换为访问令牌及其密钥。
消费方向服务提供方发起一个HTTP请求以获取访问令牌。服务提供方的文档指定了所使用的HTTP方法,建议使用POST。请求必须按照签署请求签署,并包含以下参数:
oauth_consumer_key:消费方键值。
oauth_token:之前获取的请求令牌。
oauth_signature_method:消费方签署本请求所用的签名方法。
oauth_signature:签名字符串。
oauth_timestamp:请求时间戳。
oauth_nonce:单次值。
oauth_version:可选。如果存在,其值必须为1.0。如果参数不存在,服务提供方必须假定协议版本为1.0。 服务提供方对1.0以外取值的响应尚未定义。
请求访问令牌时,不得包含其他服务提供方指定的附加参数,以确保所有令牌相关信息都是之前用户确认时存在的。
服务提供方必须确保:
请求签名验证成功;
请求令牌从未被交换过访问令牌;
请求令牌与消费方键值相符。
如果成功,服务提供方生成访问令牌及其密钥,并在HTTP响应体中返回,响应包含如下参数:
oauth_token:访问令牌。
oauth_token_secret:令牌密钥。
附加参数:服务提供方指定的附加参数。
消费方保存访问令牌及其密钥,并用以签署对受保护资源的请求。
如果请求验证失败或由于其他原因被拒绝,服务提供方应当回应以适当的响应代码,见HTTP响应代码 (HTTP响应代码)。服务提供方可以在响应体内包含关于被拒绝原因的详细信息。
成功收到访问令牌及其密钥后,消费方即可代表用户访问受保护资源,每次访问的参数有服务提供方文档提供,一般包含如下参数:
oauth_consumer_key:消费方键值。
oauth_token:访问令牌。
oauth_signature_method:消费方签署本请求所用的签名方法。
oauth_signature:签名字符串。
oauth_timestamp:请求时间戳。
oauth_nonce:单次值。
oauth_version:可选。如果存在,其值必须为1.0。如果参数不存在,服务提供方必须假定协议版本为1.0。 服务提供方对1.0以外取值的响应尚未定义。
附加参数:服务提供方指定的附加参数。
上述分四个阶段,前三个阶段就是OAUTH授权流程,第四个阶段属于消费方获得访问令牌Access Token后具体访问资源的流程。授权流程的三个请求步骤就是针对OAUTH的三个URL服务地址发出请求。每个步骤分别请求一个URL,并且收到相关信息,并且拿到上步的相关信息去请求接下来的URL直到拿到Access Token。具体的流程步骤如下图所示:
具体每步执行信息如下:
A. 消费方(第三方应用)向OAUTH服务提供方请求未授权的Request Token。向Request Token URL发起请求,请求需要带上的参数见上图。
B. OAUTH服务提供方同意消费方的请求,并向其颁发未经用户授权的oauth_token与对应的oauth_token_secret,并返回给消费方。
C. 消费方向OAUTH服务提供方请求用户授权的Request Token。向User Authorization URL发起请求,请求带上上步拿到的未授权的token与其密钥。
D. OAUTH服务提供方将引导用户授权。该过程可能会提示用户,你想将哪些受保护的资源授权给该应用。此步可能会返回授权的Request Token也可能不返回。如Yahoo OAUTH就不会返回任何信息给消费方。
E. Request Token 授权后,消费方将向Access Token URL发起请求,将上步授权的Request Token换取成Access Token。请求的参数见上图,这个比第一步A多了一个参数就是Request Token。
F. OAUTH服务提供方同意消费方的请求,并向其颁发Access Token与对应的密钥,并返回给消费方。
G. 消费方以后就可以使用上步返回的Access Token访问用户授权的资源。
从上面的步骤可以看出,用户始终没有将其用户名与密码等信息提供给消费方(第三方应用),从而更安全。用OAUTH实现背景一节中的典型案例:当服务 B(打印服务)要访问用户的服务A(图片服务)时,通过OAUTH机制,服务B向服务A请求未经用户授权的Request Token后,服务A将引导用户在服务A的网站上登录,并询问用户是否将图片服务授权给服务B。用户同意后,服务B就可以访问用户在服务A上的图片服务。 整个过程服务B没有触及到用户在服务A的帐号信息。如下图所示,图中的字母对应OAUTH流程中的字母:
OAUTH标准提出到现在不到两年,但取得了很大成功。不仅提供了各种语言的版本库,甚至Google,Yahoo,Microsoft等等互联网大头都实现了OAUTH协议。通常OAUTH服务的提供方都提供了封装好的公开API,也即所谓的SDK,开发通用应用时,可以直接拿来使用,不用根据其文档自己去实现。下面是新浪微博的授权流程图