只要是对结果第三方公共平台,都不会对 OAuth2.0 协议感到陌生,他是目前最为流行的授权机制,用来授权第三方应用在平台上进行某些受限的操作。 那么,OAuth2.0 存在的意义是什么,又是怎么样的一种授权机制呢?本文我们就来详细介绍一下。
现在我们正在使用一个阅读 APP,他可以从你的网盘的某个指定目录中直接获取其中保存的所有电子书。 那么,这个 APP 需要登录到我们的网盘中,最简单的方法是我们在 APP 中通过账号密码登录我们的网盘,此时,APP 可以将我们的账号和密码保存甚至上传,这是十分不安全的一件事,因为拥有我们账号密码的 APP 可以对我们的网盘进行一切操作,但我们并不知道,甚至 APP 可以将我们的账号密码泄露出去,后果不堪设想。 就算我们完全信任这个 APP,但如果我们需要使用很多个这样的 APP,某天我们想收回授权,唯一要做的只能是更改密码,但这样做以后所有的 APP 都无法再访问我们的云盘,这是极为不利于管理的。
上面我们就阐述了通过共享账号密码给第三方实现授权存在的问题:
解决上面的问题,我们可以引入令牌机制:
上述的过程中,与上文所描述的账号密码授权有着显著的不同:
这就是 OAuth 标准的基本思想。 令牌的出现,让平台给第三方应用的授权做到了随时可控,保证了用户信息和平台本身的安全。
RFC6749(https://tools.ietf.org/html/rfc6749)详细描述了 OAuth2.0 标准的整个授权过程。
OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者。 整个过程非常简单:
其中最为重要的环节就是令牌的颁发。 RFC-6749 协议中,规定了四种获取令牌的方式:
授权码方式是最常用的令牌颁发流程,流程相对复杂,但安全性是四种方式中最高的。 通常我们使用的授信服务基本上都是通过这种方式来颁发令牌的。
上图展示了整个令牌颁发的时序,存在以下交互过程。
在这种方式中,用户、第三方服务器、授权服务器三方进行了三次握手,并在三方中传递了授权码,最终授权码校验、颁发令牌的流程可以保证第三方服务所持有的用户授权的可信度,因此极大的保证了授权的安全性。
有一些 web 应用时纯前端应用,没有后端服务器,此时显然不能使用上述授权码的流程来颁发令牌了。 OAuth2.0 标准同样允许直接向前端颁发令牌,因为这种方式隐藏了授权码获取的相关步骤,因此被命名为“隐藏式”。
正如上文所述,我们看到,隐藏式颁发令牌的流程时序图与授权码的方式十分接近,只是省去了第三方服务器通过授权码获取令牌的流程,取而代之的,在前面一步传递授权码时直接颁发令牌。 由于整个过程都是在 HTTP 协议之上进行的,既然隐藏式是为了解决第三方客户端是纯前端应用的场景,那么,通过锚点(Fragment)传输令牌而不是通过参数传输就会更加安全,因为在 HTTP 协议中,锚点(Fragment)的跳转是由浏览器控制的,浏览器并不会将锚点传递给服务器,从而避免了令牌在请求中的传递。
HTTP/1.1 302 Found Location: http://techlog.cn#access\_token=ACCESS\_TOKEN
这种方式把令牌直接传给前端,是很不安全的,因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间有效,浏览器关掉,令牌就失效了。 微信小程序等这些纯前端的应用通常都是通过这种方式获取授权的。
如果你高度信任某个应用,且上述两种方法都因为各种原因无法使用,那么,OAuth2.0 标准允许用户直接将让第三方应用持有用户的用户名和密码来申请令牌。 交互流程十分简单,第三方应用只需通过用户的用户名、密码及自身的 client_id 作为参数请求,授权服务器直接在请求响应体中返回 access_token。
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=password&username=johndoe&password=A3ddj3w
这是最不安全的一种授权方式,平台服务通常也都不提供这种授权方式。 不过,如果授权服务器建立前,资源服务器已经长期被第三方应用直接使用用户的用户名和密码来进行访问,那么,暂时通过密码式的授权方式接入到授权服务器,此后再逐步更改为上述两种授权方式,将是一种代价比较小的迁移方式。
最后一种方式是凭证式,适用于没有前端的命令行应用,即在命令行下请求令牌。 第三方应用直接向授权服务器发送已受信的客户端凭证,与密码式一样,授权服务器直接在响应体中返回令牌。
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=client_credentials
这种授权方式不针对某个用户,通常是授权给平台信任的应用,例如需要获取平台用户数等基本信息等。
获取到令牌后,第三方应用就可以去请求资源服务器上已被授权的资源了,只需在每次请求的 header 中都带有令牌即可:
curl -H "Authorization: Bearer ACCESS_TOKEN" "https://resource.techlog.cn"
令牌有效期到了以后,如果让用户再次重复上述流程来申请新的令牌,显然非常繁琐而体验不好。 OAuth2.0 允许第三方应用自动更新令牌。 授权服务器在 access_token 下发时,一并下发了另一个令牌 — refresh_token,他就是用来更新令牌的。 在 access_token 失效前,第三方应用可以使用 refresh_token 请求授权服务器来获取新的令牌:
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
https://tools.ietf.org/html/rfc6749。