【51CTO.com原创稿件】在互联网蓬勃发展的今天,互联网应用层出不穷,每个应用专注的领域和方法也不相同。

图片来自 包图网

为了给用户更好的使用体验,一个互联网应用会请求用户授权获取另外一个应用,在获取授权之后就可以获取其他应用的资源,从而更好的为用户服务。

OAuth 2.0 就是帮助用户新型第三方应用授权的协议,今天会给大家介绍 OAuth 2.0 的实现原理和协议授权规范。

包括如下内容:

  • 从简单的例子了解 OAuth

  • OAuth 2.0 的定义和组成

  • OAuth 2.0 的 Refresh Token

  • OAuth 2.0 的授权模式

从简单的例子了解 OAuth

在介绍 OAuth 2.0 之前,让我们来看一个简单的例子。假设你平时喜欢照相,将生活中的点点滴滴记录成电子照片并且存放到云盘上,每隔一段时间会将心仪的照片挑选出来进行打印保存。

同时你发现网络上面有一个款云打印照片的应用,只需要导入电子照片,这款应用就可以帮你进行打印然后将成片邮寄到你的家中。

我们将这个例子中的授权部分抽离出来形成图 1 ,如图 1 所示,左边是云打印的部分,也就是我们需要使用的互联网服务。右边绿色的部分是用户,也就是电子照片的资源拥有者。

图 1:云打印服务的授权过程

针对云盘而言有两个服务需要提供,一个是授权服务,也就是通过照片的所有者授权第三方应用使用照片资源,另一个就是资源服务本身,也就是照片资源的提供者。

通过图 1 的展示我们将整个请求云打印服务和授权的过程分为如下几个步骤:

  • 用户请求云打印服务,此时运用只是单纯地请求服务,但是并没有提供电子照片的资源给云打印服务。

  • 云打印服务接收到请求以后,由于没有电子照片云盘的访问权限,于是请求用户对云盘进行授权。

  • 用户为了实现云打印服务,随之授权云打印去访问云盘中的电子照片。

  • 云打印将用户的授权告诉云盘中的授权服务。

  • 授权服务得知用户授权云打印服务可以打印用户在云盘中的照片时,返回给云打印服务访问权限。

  • 拿到访问照片资源权限的云打印服务,利用该访问权限访问云盘上面的电子照片资源。

  • 云盘上的资源服务接收到待访问权限的请求之后,返回电子照片,随后云打印服务开始打印服务。

OAuth 2.0 的定义和组成

从上面这个小例子可以发现当用户访问第三方的网络应用(云打印)的时候,需要通过授权的方式让云打印具备访问云盘资源的权限。

授权过后云盘的授权服务会返回给云打印应有的权限,注意这里并没有返回给云打印所有云盘权限。

例如:添加、删除、修改电子照片,只是根据用户的授权给了云打印部分的权限,也就是获取电子照片的权限。

为什么要经过这个授权的过程能,可以对其做如下分析:

  • 如果为了打印照片,用户将访问云盘的用户名密码都交给云打印服务显然不太安全。

  • 云打印在获得用户云盘授权的时候并不是获取所有的权限,而是获取部分权限,这个权限只是能够访问电子照片而已,而且通常而言还可以设置该权限的访问时长,例如:2 小时或者 1 天,从而保证打印服务的正常进行。

  • 如果此时云打印通过得知用户名和密码的方式访问云盘,那么云打印的系统被黑,就会导致云盘的资源被泄漏。

鉴于上面三点的分析,我们需要使用 OAuth 的方式进行授权。OAuth 认证是为了做到第三方应用在未获取到用户敏感信息(如:账号密码、用户 PIN 等)的情况下,能让用户授权予它来访问开放平台中的资源接口。

之所以使用 OAuth 2.0,是因为 OAuth 1.0 协议太复杂、易用性差较难普及。OAuth 2.0 通过新的协议设计,使用更加简单,更加容易普及。

在对 OAuth 2.0 协议的设计目的了解之后,再来看看它的组成部分。把上面一节中提到的例子进行映射可以将其分为 4 个组成部分。

图 2:OAuth 2.0 执行流程

如图 2 所示:

  • Client:作为访问应用的客户端,也就是需要经过授权才能访问资源的应用程序,在例子中就是第三方应用(云打印)。

  • Resource Owner:即资源所有者,例子中的用户,他可以授予第三方应用(云打印)也就是 Client,对受保护资源的访问权限的实体。

  • Authorization Server:即授权服务器,其作用是在 Resource Owner 验证并给予 Client 授权后,通过 Authorization Server 向 Client 颁发访问的令牌。

  • Resource Server:即资源服务器,它是用来存放资源的,在例子中用来存放电子照片,当 Client 使用令牌访问它的时候,它会接受响应并返回 Resource Owner 所保护的资源,也就是电子照片。

其中 Authorization Server 和 Resource Server 可以分开,也可能存在同一个服务器上面。按照上面的例子,这两部分都属于云盘服务器。

上面介绍了 OAuth 2.0 的几个组件,这里再将图 2 中的执行流程给大家进行讲解:

  • 客户端(Client)向资源所有者(Resource Owner)请求授权。

  • 客户端(Client)收到用户授权,这是代表资源所有者(Resource Owner)授权的凭证(Authorization)。

  • 客户端(Client)通过与授权服务器(Authorization Server)进行身份验证并提供授权许可来请求访问令牌(Access Token)。

  • 授权服务器(Authorization Server)对客户端进行身份验证并验证授权许可,如果有效,则颁发访问令牌(Access Token)。

  • 客户端(Client)从资源服务器(Resource Server)请求受保护的资源并通过提供访问令牌(Access Token)进行身份验证。

  • 资源服务器(Resource Server)验证访问令牌(Access Token),如果有效,则为请求提供服务。

通过上面的流程 Client 终于可以拿到 Resource Server 上的资源为 Resource Owner 提供对应的服务了。

这整个过程称为授权许可,它代表资源的凭证所有者(Resource Owner)授权给客户端(Client)访问其受保护的资源,以及客户端获取访问令牌的整个过程。

OAuth 2.0 的 Refresh Token

上面说道资源服务器(Resource Server)是通过验证客户端(Client)的访问令牌(Access Token)来提供资源服务的,因此访问令牌(Access Token)就是访问受保护资源的凭据。

它是一个字符串,并由授权服务器(Authorization Server)颁发客户端(Client)的,同时会指定资源访问范围和持续时间。

正因为如此访问令牌(Access Token)在超出范围,特别是超出访问时间的时候会出现失效的情况,此时客户端就需要获得额外的访问令牌(Access Token)。

此时授权服务器会给客户端发出刷新令牌(Refresh Token),与访问令牌(Access Token)不同的是刷新令牌(Refresh Token)仅用于授权服务器,从不发送 到资源服务器。

在后面会提到的授权码模式中,授权服务器会同时返回刷新令牌(Refresh Token)。

其目的是在访问令牌( Access Token)过期前,重新获取新的访问令牌(Access Token),不需要资源所有者(Resource Owner)重新确认授权,提高了授权效率和用户体验。

在访问令牌( Access Token) 前, 客户端(Client)可用刷新令牌(Refresh Token)向授权服务器(Authorization Server)发送请求。

图 3

如图 3 所示,假设 b.com 是授权服务器(Authorization Server)地址,请求包含如下内容:

收到 grant_type:授权类型,值为 ‘refresh_token’。

client_id:客户端 id,即客户端(Client)在授权服务器上注册被分配的 id。

client_secret:客户端(Client)和授权服务器(Authorization Server)通行的密钥,由授权服务器颁发,在特殊需要确认的情况下需要作为验证条件。

refresh_token:用户获取新的 access_token 的 refresh_token。

OAuth 2.0 的授权模式

前面给大家介绍了 OAuth 2.0 的定义和组成结构,并且详细描述了其授权的流程,并且提出了 Access Token 过期情况下 Refresh Token 的解决方案。

接下来介绍 OAuth 2.0 的授权模式,也就是资源所有者将资源的使用权限授予给客户端的方式。

这里列举 4 种授权模式,分别是:

  • 授权码模式

  • 隐含授权模式

  • 密码模式

  • 客户端模式

①授权码模式(Authorization Code)

它是功能最完整、流程最严密的授权模式,其特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。

授权码模式会使用两种访问权限令牌(Access Token)和刷新令牌(Refresh Token),授权过程基于重定向的流。

客户端(Client)能够从资源所有者(Resource Owner)的用户代理(User Agent)接收传入的请求。

然后通过重定 URI 发送给授权服务器(Authorization Server),并获取返回的访问令牌(Access Token)。

图 4:授权码模式流程图

如图 4 所示,这里将授权码模式的流程处理分为 5 个步骤:

  • 客户端(Client)初始化流程,将资源所有者对应的用户代理(User Agent 浏览器)指向授权服务器(Authorization Server)。

此时客户端(Client)包含了本身的 ID、请求范围、本地状态以及重定向的URI的信息。这个 URI 是告诉授权服务器(Authorization Server)在授权完成之后回调用户代理的 URI。

  • 用户代理(User Agent)会发送给授权服务器(Authorization Server)用户的身份信息。

授权服务器(Authorization Server)会对资源所有者(Resource Owner)的身份进行认证,然后返回是否授权的结果。

  • 假设授权服务器(Authorization Server)通过了资源所有者的授权,它将授权码(Authorization Code)以及一些状态信息通过重定向URI通过用户代理返回给客户端(Client)。

  • 客户端收到授权码(Authorization Code),附上重定向的URI向授权服务器(Authorization Server)申请访问令牌(Access Token)。

同时也会附上重定向的 URI,当返回访问令牌(Access Token)的时候能够找到对应的客户端(Client)。

  • 认证服务器(Authorization Server)核对了授权码(Authorization Code)确认无误后,通过重定向的URI向客户端发送访问令牌(Access Token)和更新令牌(Refresh Token)。

后面的过程就是客户端使用访问令牌(Access Token)访问资源服务器(Resource Server)了。

通过上面对授权码模式的介绍,我们不仅会提出一个问题,客户端为什么要获取授权服务器中的授权吗?

再用这个授权码向授权服务器申请获取访问令牌,授权服务器直接把访问令牌发给客户端不久完了吗,非要绕着么大一圈不是多次一举吗?

这里对这一原因进行解释如下:用户代理在显示中都以浏览器的方式存在,而浏览器中对应的重定向 URI(redirect_uri)被认为是不安全信道,此方式不适合敏感数据-访问令牌的传输。

因为 URI 有可能通过 HTTP referrer 传递到其它恶意站点,也可能存在于浏览器 cacher 或 log 文件中,这就给攻击者盗取访问令牌提供了便利。

这里还有一个假设,就是设资源所有者的行为虽然是可信赖的,但是资源所有者所使用的用户代理,也就是浏览器可能早已被攻击者植入了跨站脚本用来监听访问令牌。

此时将访问令牌用户代理传递给客户端,会扩大访问令牌被泄露的风险。但授权码(Authorization Code)是可以通过重定向 URI 来传递的。

授权码并不像访问令牌那样敏感,即使授权码泄露了,攻击者也无法直接拿到访问令牌从而访问资源。因为拿到授权码去交换访问令牌时是需要验证客户端真实身份的。

说白了就是除了客户端之外,其他人拿授权码事没有用的。这也事为什么访问令牌只能发给客户端使用的原因,其他任何主体包括资源所有者都不应该获取访问令牌。

协议的设计保证客户端是唯一有能力获取访问令牌的主体。引入授权码的目的也是为了保证客户端是访问令牌的唯一持有人。

另外,由于协议需要验证客户端的身份,如果不引入授权码,客户端的身份认证只能通过重定向 URI 来传递。

由于重定向 URI 是一个不安全信道,就额外要求客户端必须使用数字签名技术来进行身份认证,而不能用简单的密码或口令认证方式。

引入授权码之后,授权服务器可以直接对客户端进行身份认证,可以支持任意的客户端认证方式。

可以理解为授权码作为客户端和资源所有者之间的中介,用来验证客户端的身份。

②隐式授权模式(Implicit Grant )

它是一种简化模式,由于前面一种模式需要通过授权码换取访问令牌的方式实现授权,在提升安全性的同时增加了复杂度。

因此隐式授权模式会直接在用户代理(浏览器)中向授权服务器申请访问令牌,跳过了授权码这个步骤,所有步骤在浏览器中完成,访问令牌对访问者是可见的,且客户端不需要认证。

图 5:隐式授权模式流程图

如图 5 所示,我们一起来看看隐式授权模式的执行流程:

  • 客户端(Client)初始化流程,将资源所有者对应的用户代理(User Agent 浏览器)指向授权服务器(Authorization Server)。

  • 此时客户端(Client)包含了本身的 ID、请求范围、本地状态以及重定向的URI的信息。这个 URI 是告诉授权服务器(Authorization Server)在授权完成之后回调用户代理的 URI。

  • 用户代理(User Agent)会发送给授权服务器(Authorization Server)用户的身份信息,授权服务器(Authorization Server)会对资源所有者(Resource Owner)的身份进行认证,然后返回是否授权的结果。

  • 假设授权服务器(Authorization Server)通过了资源所有者的授权,它将访问令牌(访问令牌)使用重定向 URI 通过用户代理返回给客户端(Client)。

  • 用户代理(User Agent)通过重定向的 URI 被指向到 Web 所托管的客户端资源上。

  • Web 所托管的客户端资源会返回一个 Web 页面,该页面是一个带有 Script 脚本的 HTML 文档,其中包含可以访问所有资源的访问令牌(Access Token)。

  • 用户代理(User Agent)也就是浏览器,在接收到返回的 Script 以后,从中抽取需要的访问令牌(Access Token)。

  • 随后用户代理(User Agent)将访问令牌(Access Token)传给客户端(Client),继续后续的资源获取工作。

正如前面提到的隐式授权模式简化了授权码获取的过程,通过 Web 托管客户资源返回的 Script 脚本中携带了对应的访问码,用户代理在抽取访问码之后返回给客户端调用资源。

这种方式虽然省去了获取授权码的过程,但是在用户代理中存放了访问码存在一定的安全风险。

③密码模式(Resource Owner Password Credentials Grant)

用户向客户端提供自己的用户名和密码。客户端使用这些信息,向授权服务器索要授权。在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。

这通常用在用户对客户端高度信任的前提下才能进行,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

图 6:密码模式流程图

接下来我们一起看看密码模式的执行流程,如图 6 所示,整个过程比较简单分为 3 个步骤:

  • 资源所有者向客户端提供用户名和密码

  • 客户端将从资源所有者处获取的授权(用户名+密码)发送给授权服务器,从而获取访问资源服务器的权限。

  • 授权服务器确认资源所有者的授权(用户名+密码)之后返回访问令牌以及刷新令牌。

④客户端模式(Client Credentials Grant)

指客户端以自己的名义,而不是以用户的名义,向授权服务器进行认证。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求授权服务器提供服务,不存在授权问题。

由于不存在资源所有者的授权行为,因此这种模式严格上来说不属于 OAuth 2.0 的模式范畴。客户端在授权服务器上存在可控资源的情况,才能使用这种方式。

图 7:客户端模式流程图

如图 7 所示,这种模式分为 2 步:

  • 客户端自身向授权服务器发起授权请求,申请获取访问令牌。

  • 授权服务器在经过认证授权以后发送给客户端访问令牌。

总结

本文从云打印照片的例子开始,通过用户授权云打印服务访问云盘获取电子照片的整个过程,带出了 OAuth 2.0 所实现的资源授权与访问的功能。

然后提出 OAuth 2.0 是用来保证第三方应用授权访问资源安全性的协议,其协议会涉及到客户端、资源所有者、授权服务器和资源服务器,并且描述了授权过程如何在它们之间展开的。

在介绍完授权流程之后,又进一步说明了在过程中获取访问令牌才能访问资源,如果令牌过期的情况下需要通过刷新令牌保持授权的有效性。

最后介绍了 OAuth 2.0 的 4 种授权模式,分别是授权码模式、隐含授权模式、密码模式和客户端模式,以及它们的实现流程。

【51CTO原创稿件,合作站点转载请注明原文作者和出处为51CTO.com】