OAuth(Open Authorization,开放的授权协议)是一个安全的、开放而简易的用户资源授权协议。OAuth 协议有三大特征:
互联网很多服务,如:Open API,很多大公司,如:Google,Yahoo,Microsoft 等都提供了 OAuth 认证服务。
举一个典型案例:如果一个用户需要两项服务,图片在线存储服务 A、图片在线打印服务 B。假设服务 A、服务 B 由两家不同的服务提供商提供,所以用户需要在这两家服务提供商的网站上分别注册两个用户名、密码各不相同的账户。
当用户要使用服务 B 打印存储在服务 A 上的图片时,用户该如何处理?
方式 1:用户先将图片从服务 A 下载到本地,然后上传到服务 B 上打印,这种方式安全但处理比较繁琐,效率低下;
方式 2:用户将在服务 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 日发布与 IETF(国际互联网工程任务组),编号是 RFC5849,标志着 OAuth 正式成为互联网标准协议。
第三方应用登录流程:
OAuth 在 Client 与 Resource server 之间设置了一个授权层(Authorization Layer)。Client 不能直接登录 Resource server,只能登录 Authorization server。上述步骤 2 是整个流程的关键,有了这个授权以后,客户端就可以获取令牌继而凭令牌获取资源。
令牌(token)与密码(password)都用于身份认证,但有三点差异:
OAuth2 是 OAuth1.0 的升级版本,但不向前兼容 OAuth1.0,即完全废止了 OAuth1.0。2012 年 10 月,OAuth 2.0 协议正式发布为 RFC 6749。当下百度开放平台,腾讯开放平台等大部分的开放平台都使用了 OAuth 2.0 协议。
授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。
这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。
举例说明:我作为一个用户在使用网站 A,并希望通过网站 A 直接访问 B 的资源,此时 B 会要求 A 提供我的用户信息,例如:弹出 QQ 账户的登录授权窗口。我把 QQ 账户登录成功后,表示我答应了 A 可以访问 B 中属于我自身的资源。我向 B 证明了合法的身份后,B 同时向 A 发放了一个令牌(Token),A 拿着这个 Token 就可以有限的时间内访问网站 B 中有限的资源。
有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。隐藏式授权,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为 “授权码隐藏式(implicit)”。
这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。
如果你高度信任某个第三方应用,密码式授权允许用户把用户名和密码直接告诉该第三方应用。该应用就使用你的密码,申请令牌,这种方式称为 “密码式(password)”。
凭证式授权指客户端以自己的名义,而不是以用户的名义,向 “服务提供商” 进行认证。严格地说,客户端模式并不属于 OAuth 协议所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求 “服务提供商” 提供服务,其实不存在授权问题。
所以,凭证式授权仅仅适用于没有前端的命令行应用,即在命令行下请求令牌。这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。
令牌的有效期到了,如果让用户重新走一遍上述的流程,用户体验必然不好。OAuth 2.0 允许用户自动更新令牌。具体方法是:网站 B 颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(refresh token 字段)。令牌到期前,用户使用 refresh token 发一个请求,去更新令牌。
https://b.com/oauth/token?
grant_type=refresh_token&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
refresh_token=REFRESH_TOKEN
上面 URL 中,grant_type 参数为 refresh_token 表示:要求更新令牌。client_id 参数和 client_secret 参数用于确认身份。refresh_token 参数就是用于更新令牌的令牌。网站 B 验证通过以后,就会颁发新的令牌。