【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】