OAuth 2.0中文译本
(一)背景知识
OAuth 2.0很可能是下一代的“用户验证和授权”标准,目前在国内还没有很靠谱的技术资料。为了弘扬“开放精神”,让业内的人更容易理解“开放平台”相关技术,进而长远地促进国内开放平台领域的发展,笔者特意将OAuth 2.0协议翻译成中文。
目前OAuth 2.0还没有最后定稿,最新的修改版是第11个版本,本文下面的翻译即基于这个第11版本。原文见http://tools.ietf.org/html/draft-ietf-oauth-v2-11。
关于OAuth 2.0的更多背景知识,请参考我的另一篇文章:http://itgeeker.com/mathml/readpaper?pid=65
(二)术语中英对照表
由于OAuth协议版本较多(1.0,1.0a,2.0等),并且各个版本中的技术术语也各不相同,关于英文技术术语与中文的对应关系,我们以OAuth 2.0的第11版本中的描述为准。
另外有一些情况,一些英文术语不容易找到普遍接受的汉语释义,翻译过来反而可能引起误解,而英文术语本身可能更容易理解,因此就不考虑对这部分词汇做翻译了。比如,“web service”、“endpoint”、“user-agent”、“URI”、“cookie”等,你只需要知道它是什么就好了。
还有一些特别难于翻译的词汇,比如“profile”,这个词用在协议里,大概表示:协议功能的某个剖面、子集、子视图或轮廓。如果翻译成“视图”,容易让人想到“view”这个词,产生冲突,最后,我在这里创造了一个新词汇:“子态”。
下面是整理出来的重要技术术语的中英对照表:
云计算 —— cloud computing
第三方 —— third-party
应用/程序 —— application
私有证书 —— credential
身份验证 —— authentication
授权 —— authorization
明文 —— clear-text
客户端 —— client {译者注:本文中的客户端与平常所说的“客户端”并不相同,是相对资源服务器和授权服务器来说的,它可能指第三方应用的服务器程序或客户端程序}
服务器 —— server
资源拥有者 —— resource owner
受保护资源 —— protected resource
资源服务器 —— resource server
访问令牌 —— access token
授权服务器 —— authorization server
访问许可 —— access grant
实体 —— entity
签名 —— signature
刷新令牌 —— refresh token
作用域 —— scope
授权码 —— authorization code
标识符 —— identifier
密钥 —— secret
断言 —— assertion
原生程序 —— native application
子态 —— profile
同源策略 —— same-origin policy
回调 —— callback
自治的 —— autonomous
查询参数部分 —— query component
分段参数部分 —— fragment component
媒体类型 —— media type
厂商特性的 —— vendor-specific
增强型巴科斯范式 —— ABNF
互联网编号分配机构 —— IANA
互联网工程指导组 —— IESG
标准轨道 —— standards-track
(三)中文译本
1. 引言
随着分布式web service和云计算的使用越来越多,第三方应用需要能访问到一些服务器托管资源。这些资源通常都是受保护的,并且要求使用资源拥有者的私有证书(典型的证书是用户名和密码)进行身份验证。
在传统的基于客户端-服务器的身份验证模型中,客户端为了访问服务器的受保护资源,是使用资源拥有者的私有证书来做身份验证的。为了让第三方应用能够访问受保护资源,资源拥有者必需将他/她/它的私有证书透露给第三方。这引出了很多问题并存在很多局限性:
<!--[if !supportLists]-->· <!--[endif]-->第三方应用需要用明文保存资源拥有者的私有证书(一般是密码),留作以后再次使用。
<!--[if !supportLists]-->· <!--[endif]-->虽然密码验证会造成安全隐患,服务器仍然需要支持用密码做身份验证(对称的密码验证)。
<!--[if !supportLists]-->· <!--[endif]-->第三方应用对资源拥有者的受保护资源获得过多的使用权限,而资源拥有者没有能力限制访问到某个资源子集,限制持续时间,或限制这些资源所能支持的访问方式。
<!--[if !supportLists]-->· <!--[endif]-->资源拥有者无法在不影响所有第三方的前提下单独撤销某个第三方的访问权限,他/她/它只能通过修改密码来回收所有权限。
OAuth通过将客户端和资源拥有者的角色进行分离来解决这些问题。在OAuth中,客户端(通常不是资源拥有者,而是代表资源拥有者来操作)提出请求来访问由资源拥有者控制并由资源服务器托管的资源,然后得到与资源拥有者不同的一套私有证书。
客户端并不是直接使用资源拥有者的私有证书来访问受保护资源,而是得到一个访问令牌——一个代表某一特定作用域、持续时间和其它属性的字符串{译者注:非常重要的一个概念,英文叫access token}。访问令牌由授权服务器在资源拥有者的授意下分发给第三方客户端。客户端使用访问令牌来访问由资源服务器托管的受保护资源。
例如,一个web用户(资源拥有者)能够准许一个打印服务(客户端)访问她存储在另一个照片共享服务(资源服务器)中的照片,而不用将她的用户名和密码透露给这个打印服务。她在一个被该照片分享服务信任的身份验证服务(授权服务器)上完成验证,而这个验证服务会将特定于委托服务的私有证书(令牌)分发给原打印服务。
基于资源服务器对安全的需求,访问令牌可以有不同的格式、结构和使用方式(例如密码学特性)。访问令牌的属性和用以访问受保护资源的方式不在本规范的规定范围之内,而是由相关的其它规范来定义。授权服务器和资源服务器之间的交互方式不在本规范的规定范围之内。
1.1. 符号规范
这篇文档中的关键词“必须”、“一定不能”、“要求”、“会”、“不会”、“应该”、“不应该”、“建议”、“可以”、“可选的”,遵从[RFC2119]中的解释。
这篇文档使用出自[I-D.ietf-httpbis-p1-messaging]的增强型巴科斯范式(ABNF)标记法。另外,介绍一些规则定义的出处:URI-Reference出自[RFC3986];OWS、RWS和quoted-string出自[I-D.ietf-httpbis-p1-messaging]。
除非特别提到,否则所有协议参数的名字和值都是大小写敏感的。
1.2. 专业术语解释
受保护资源:能够使用OAuth请求获取的访问限制性资源。
资源服务器:能够接受和响应受保护资源请求的服务器。
客户端:获取授权和发送受保护资源请求的应用。
资源拥有者:能够对受保护资源进行访问许可控制的实体。
终端用户:起到资源拥有者角色的用户。
令牌:分发给客户端的代表访问授权的字符串。通常这个字符串对客户端来说是不透明的。令牌代表资源拥有者许可的访问作用域和持续时间,并由资源服务器和授权服务器强制保证。这个令牌可以代表一个标识符,用于检索授权信息,或以一种可验证的方式自包含授权信息(即一个包含数据和签名的令牌字符串)。令牌可能只代表纯粹的访问能力。而为了让客户端使用令牌,也可能需要一些多余的特定验证证书。
访问令牌:被客户端用来代表资源拥有者发送验证请求的令牌。
刷新令牌:被客户端用来获取新的访问令牌的令牌,而不用资源拥有者的参与。
授权码:一个短期令牌,代表终端用户的授权。授权码用于获取一个访问令牌和一个刷新令牌。
访问许可:用于描述中间形式的私有证书(如终端用户的密码或授权码)的一个通用词汇,代表资源拥有者的授权。客户端使用访问许可来获取访问令牌。通过将各种形式的访问许可都交换成访问令牌,资源服务器只需要支持一种验证机制。
授权服务器:能够成功验证资源拥有者和获取授权,并在此之后分发令牌的服务器。授权服务器可以和资源服务器是同一个服务器,也可以是不同的实体。单独一个授权服务器可以为多个资源服务器分发令牌。
终端用户授权endpoint:授权服务器上能够验证终端用户并获取授权的HTTP endpoint。终端用户授权endpoint在第4节详细描述。
令牌endpoint:授权服务器上能够分发令牌和刷新过期令牌的HTTP endpoint。令牌endpoint在第5节详细描述。
客户端标识符:分发给客户端的唯一标识,用于客户端向授权服务器标识自己。客户端标识符可以有一个对应的密钥。客户端标识符在第3节详细描述。
1.3. 概述
OAuth为客户端提供了一种代表资源拥有者访问受保护资源的方法。在客户端访问受保护资源之前,它必须先从资源拥有者获取授权(访问许可),然后用访问许可交换访问令牌(代表许可的作用域、持续时间和其它属性)。客户端通过向资源服务器出示访问令牌来访问受保护资源。
访问令牌提供了一个抽象层,将不同的授权结构(如用户名密码、断言)替换成资源服务器可以理解的单一令牌。这种抽象使得分发短期有效的访问令牌成为可能,也使得资源服务器不必理解多种多样的授权机制。
<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter"/> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"/> <v:f eqn="sum @0 1 0"/> <v:f eqn="sum 0 0 @1"/> <v:f eqn="prod @2 1 2"/> <v:f eqn="prod @3 21600 pixelWidth"/> <v:f eqn="prod @3 21600 pixelHeight"/> <v:f eqn="sum @0 0 1"/> <v:f eqn="prod @6 1 2"/> <v:f eqn="prod @7 21600 pixelWidth"/> <v:f eqn="sum @8 21600 0"/> <v:f eqn="prod @7 21600 pixelHeight"/> <v:f eqn="sum @10 21600 0"/> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/> <o:lock v:ext="edit" aspectratio="t"/> </v:shapetype><v:shape id="图片_x0020_1" o:spid="_x0000_i1030" type="#_x0000_t75" alt="http://itgeeker.com/getimg?id=62" style='width:434.25pt;height:241.5pt; visibility:visible;mso-wrap-style:square'> <v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtmlclip1\01\clip_image001.jpg" o:title="getimg?id=62"/> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
图1: 抽象的协议流程
图1所示的抽象流程协议的总体架构,它包含下列步骤:
(A) 客户端从资源拥有者那里请求授权。授权请求能够直接发送给资源拥有者,或者间接地通过授权服务器这样的中介,而后者更为可取。
(B) 客户端收到一个访问许可,它代表由资源服务器提供的授权。
(C) 客户端使用它自己的私有证书到授权服务器上验证,并出示访问许可,来请求一个访问令牌。
(D) 授权服务器验证客户端私有证书和访问许可的有效性,如果验证通过则分发一个访问令牌。
(E) 客户端通过出示访问令牌向资源服务器请求受保护资源。
(F) 资源服务器验证访问令牌的有效性,如果验证通过则响应这个资源请求。
1.4 访问许可
访问许可代表资源拥有者提供的授权。访问许可的类型取决于客户端使用的获取方式和授权服务器所支持的方式。
1.4.1 授权码
授权码是通过将终端用户引导到授权服务器而获得的一种访问许可。授权服务器验证终端用户,获得授权,然后向客户端分发一个授权码。因为终端用户只在授权服务器上进行验证,所以终端用户的密码从来不用分享给客户端。
当客户端通过一个user-agent同终端用户进行交互的时候,授权码这种访问许可是很合适的。
<!--[if gte vml 1]><v:shape id="图片_x0020_2" o:spid="_x0000_i1029" type="#_x0000_t75" alt="http://itgeeker.com/getimg?id=63" style='width:424.5pt;height:303pt;visibility:visible;mso-wrap-style:square'> <v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtmlclip1\01\clip_image003.jpg" o:title="getimg?id=63"/> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
图2: 获取授权码
图2所示的授权码获取流程包含下列步骤:
(A) 客户端通过将终端用户的user-agent引导到授权服务器的终端用户授权endpoint来发起这个流程。客户端传入标识符、请求作用域、本地状态,和一个重定向URI(在访问被许可或被拒绝后授权服务器会重新将user-agent引导回这个URI)。
(B) 授权服务器验证终端用户的身份(通过user-agent),并且确定终端用户是许可还是拒绝了客户端的访问请求。
(C) 如果访问被许可,授权服务器会使用重定向URI将user-agent引导回客户端。授权服务器传回一个授权码给客户端,用于进一步获取访问令牌。
一旦客户端获得了授权码,它会到授权服务器上去做验证(使用客户端私有证书)并出示授权码(访问许可),以借此请求一个访问令牌。
在客户端无法维护它自己的私有证书的情况下(如原生程序或用某种user-agent脚本实现的程序),授权服务器在(C)步直接给客户端分发一个访问令牌,而不再分发一个授权码。
获得授权码的过程在第4节详述。
1.4.2 资源拥有者密码证书
资源拥有者密码证书(例如用户名和密码)可以直接用作访问许可来获取访问令牌。这种私有证书只应该在以下两种情况下使用:当在资源拥有者和客户端之间有很强的信任关系的时候(例如,资源拥有者的计算机操作系统,或具有很高特权的程序),以及当其它访问许可类型(如授权码)不可用的时候。
即使这种许可类型需要客户端直接访问资源拥有者的私有证书,资源拥有者的私有证书也只是在一个请求中使用,并交换成访问令牌。与[RFC2617]定义的HTTP Basic验证机制不同,这种许可类型不再需要客户端存储资源拥有者的私有证书以备日后使用。
<!--[if gte vml 1]><v:shape id="图片_x0020_3" o:spid="_x0000_i1028" type="#_x0000_t75" alt="http://itgeeker.com/getimg?id=64" style='width:390pt;height:73.5pt;visibility:visible;mso-wrap-style:square'> <v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtmlclip1\01\clip_image005.jpg" o:title="getimg?id=64"/> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
图3: 获取资源拥有者密码证书
在图3中,客户端直接从资源拥有者请求授权。当资源拥有者是一个终端用户时,客户端通常的做法是提示终端用户输入用户名和密码。
1.4.3 客户端私有证书
当授权作用域限制在客户端所控制的受保护资源或之前与授权服务器约定好的受保护资源时,客户端本身的私有证书可被用作访问许可。客户端私有证书用作访问许可的典型例子是,当客户端代表它自己执行操作时(客户端同时也是资源拥有者)。
1.4.4 刷新令牌
访问令牌的生命周期通常比资源拥有者授予的要短一些。当分发一个访问令牌时,授权服务器可以同时传回一个刷新令牌,在当前访问令牌超时后,客户端可以用这个刷新令牌重新获取一个访问令牌。当请求新的访问令牌时,刷新令牌担当起访问许可的角色。使用刷新令牌,不再需要再次与资源拥有者交互,也不需要存储原始的访问许可来获得访问令牌和刷新令牌。
<!--[if gte vml 1]><v:shape id="图片_x0020_4" o:spid="_x0000_i1027" type="#_x0000_t75" alt="http://itgeeker.com/getimg?id=65" style='width:425.25pt;height:311.25pt;visibility:visible;mso-wrap-style:square'> <v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtmlclip1\01\clip_image007.jpg" o:title="getimg?id=65"/> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
图4: 刷新访问令牌
图4所示的刷新令牌流程包含下列步骤:
(A) 客户端通过使用它自己的私有证书在授权服务器上验证,并出示一个访问许可。
(B) 授权服务器验证客户端私有证书和访问许可的有效性,如果通过则分发一个访问令牌和刷新令牌。
MsoNor