原文:An Introduction to OAuth 2
简介
OAuth 2 是一个授权框架,可以让应用获取一个 HTTP 服务(如 Facebook, GitHub, DigitalOcean)的用户账户的有限的访问。原理是通过持有用户账户的服务主机验证用户身份后授权第三方应用访问用户账户。OAuth 2 为 web 和桌面应用、移动设备提供授权工作流程。
这篇信息指南针对应用程序开发人员,简要说明了 OAuth 2 里的角色分类、授权类型、用例和工作流程。
从 OAuth 角色分类开始讲起。
OAuth 角色分类
OAuth 定义了4种角色:
- 资源所有者
- 客户端
- 资源服务器
- 授权服务器
接下来我们将详细描述这几个角色。
资源所有者:用户
资源所有者是授权一个应用使用他们账户的用户。应用使用用户账户受限于授予的权限范围(如:读或写权限)。
资源/授权服务器:API
资源服务器持有受保护的用户账户,由它来验证用户身份然后将访问口令传给应用。
以应用开发者的角度来看,一个服务的 API 既是资源服务器也是授权服务器。我们将这两个角色结合成服务方角色或 API 角色。
客户端:应用
客户端就是想要使用用户账户的应用。在这之前,需要经过用户授权,而授权的验证由 API 来做。
抽象协议工作流程
现在你对 OAuth 角色分类有了一些了解,接着通过一个图来看他们是如何协作的:
该图详细解释:
1、应用请求用户授权访问服务方资源。
2、如果用户授权了,应用收到授权许可。
3、应用提供可以证实自己的身份证明和授权许可向授权服务器(API)请求访问口令(access token)。
4、如果应用的身份证明和授权许可都通过了验证,授权服务器(API)发送一个访问口令给应用,授权完成。
5、应用提供访问口令从资源服务器(API)请求资源。
6、如果访问口令有效,资源服务器(API)提供资源给应用。
实际流程因授权类型不同会有不同,这是总体的思路。之后我们将探索不同的授权类型。
应用注册
在应用使用 OAuth 之前你必须在这个服务上注册你的应用。这需要通过在服务网站上填写一个『开发者』或『API』注册表单,表单需要提供以下信息(可能还有应用详细信息):
- 应用名字
- 应用网站
- 重定向 URI 或回调 URL
重定向 URI 是在用户授权(或拒绝授权)以后服务方要重定向的位置,也就是你的应用处理授权码或访问口令的地方。
客户端 ID 和客户端密钥
在你的应用注册后服务方会给你一个以客户端标志符(ID)和客户端密钥为代表的『客户端证书』。客户端 ID 是一个公开暴露的字符串,用于服务 API 标识这个应用,也用于生成授权相关的各种 URL。客户端密钥用于在应用请求访问用户账户时服务 API 鉴定应用身份,必须要保证在应用和 API 之间私有。
授权许可
在之前的抽象协议工作流程里,前四步获得授权许可和访问口令。授权许可类型依赖于应用请求授权所使用的方法和 API 支持的许可类型。OAuth 2 规定了4种批准类型,在不同的案例里使用不同的批准类型:
- 授权码:用于服务器端应用。
- 隐含:用于手机应用或网页应用(即运行于用户设备的应用)
- 资源所有者密码验证:用于受信赖的应用,如服务方自己持有的应用。
- 客户端验证:用于应用 API 访问。
接着我们要详细说下不同类型的用例和工作流程。
授权类型:授权码
授权码类型是最常用的类型,充分利用了服务器端应用代码不公开的优点,即客户端密钥可以保持私有。该模式是一种基于重定向的流程,这意味着应用必须可以和用户代理(如用户的浏览器)进行交互且要能收到用户代理转发的 API 授权码。
下面是授权码类型工作流程图:
步骤1:授权码链接
首先用户得到一个像这样的授权码链接:
https://cloud.digitalocean.com/v1/oauth/authorize?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read
链接组成部分:
- https://cloud.digitalocean.com/v1/oauth/authorize:授权 API 端点
- response_type=code:表明应用正在请求授权码
- client_id=CLIENT_ID:应用的客户端 ID(用于 API 辨认应用身份)
- redirect_uri=CALLBACK_URL:服务方在授予授权码后将用户代理重定向的位置
- scope=read:表明应用请求的权限范围
步骤2:用户授权给应用
当用户点击上面那个链接,如果没有登录的话首先应该登录到那个服务。然后服务方提示用户是否要授权给那个应用使用他们的账号。下图是一个授权提示:
上图是 DigitalOcean 的授权页面截图,可以看到『Thedropletbook』应用正在请求『[email protected]』账号的『读』权限。
步骤3:应用收到授权码
如果用户点击『授权给应用』,服务方将用户代理重定向到应用之前提供的重定向 URI,这时 URI 带有授权码。重定向的网址看起来像这样(假设应用网址是"dropletbook.com"):
https://dropletbook.com/callback?code=AUTHORIZATION_CODE
步骤4:应用请求访问口令
应用使用授权码和客户端密钥向 API 请求访问口令。下面是一个 POST 请求口令的例子:
https://cloud.digitalocean.com/v1/oauth/token?
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=CALLBACK_URL
步骤5:应用收到访问口令
如果验证通过,API 将返回一个包含访问口令的响应(和一个可选的更新口令)。完整的响应看起来像这样:
{
"access_token":"ACCESS_TOKEN",
"token_type":"bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN",
"scope":"read",
"uid":100101,
"info":{
"name":"Mark E. Mark",
"email":"[email protected]"
}
}
现在应用已经获得了授权!接下来可能使用访问口令来访问用户的账号,当然访问受所授的权限限制,直到口令到期或被取消授权。如果有收到更新口令(refresh token),可以在当前口令过期后用它来请求新的口令。
授权类型:隐式
隐式授权类型用于手机应用或 web 应用(也就是运行在 web 浏览器的应用),这类应用的客户端密钥私密性没有保障。隐式授权类型同样是基于重定向的工作流程,只是访问口令是给用户代理也就是应用的,所以访问口令可能暴露给用户和用户设备上的其它应用。同时,这个流程不需要验证应用身份,只要有重定向的 URI(在服务方那边注册了的)就可以提供这个服务了。
隐式授权类型不支持更新口令。
隐式授权类型基本工作流程如下:应用要求用户授权,然后授权服务器传回访问口令给用户代理,用户代理将其传递给应用。下图是详细点的过程图:
步骤1:隐式授权链接
在隐式授权类型里,一个向 API 请求口令的授权链接代表了用户。这个链接就像是授权码链接,只是它是请求一个口令而不是授权码(注意响应类型是口令):
https://cloud.digitalocean.com/v1/oauth/authorize?
response_type=token&
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read
步骤2:用户授权给应用
当用户点击上面那个链接,需要先登录到服务方来验证用户的身份。然后用户将看到服务方提示是否授权给应用。提示就像之前说过的那样。
步骤3:用户代理重定向到带有访问口令的指定网址
如果用户点击了『授权』,服务方将用户代理重定向到应用提供的重定向地址,重定向时包含访问口令。它看起来像这样:
https://dropletbook.com/callback#token=ACCESS_TOKEN
步骤4:用户代理遵循重定向 URI
用户代理保持带有访问口令的 URI。
步骤5:应用发送提取访问口令脚本
应用返回一个带有可以从整个重定向 URI 里提取口令的脚本的网页。
步骤6:访问口令传给应用
用户代理执行给出的脚本然后把访问口令传递给应用。
现在应用已经获得了授权!接下来可能使用访问口令来访问用户的账号,当然访问受所授的权限限制,直到口令到期或被取消授权。
授权类型:资源持有者密码验证
在这个类型里,用户直接提供他们在服务方那边的凭证(用户名和密码)给应用,用这些凭证可以从服务方那边获得访问口令。这种授权类型只有在别的授权类型不可行的时候用于授权服务器上。或者只有在应用可信的情况下使用(如服务方持有的应用或用户操作系统应用)。
密码验证流程
在用户提供凭证给应用后应用将向授权服务器请求访问口令。POST 请求看起来像这样:
https://oauth.example.com/token?
grant_type=password&
username=USERNAME&
password=PASSWORD&
client_id=CLIENT_ID
如果用户凭证通过验证,授权服务器返回访问口令给应用。现在应用已被授权!
注意:DigitalOcean 目前不支持这种授权,所以上面的链接指向虚构的授权服务器『oauth.example.com』。
授权类型:客户端验证
这种授权类型给应用提供了一种让应用自己管理服务账号的方式。使用场景是应用想要更新其注册的描述或重定向的 URI,又或者通过 API 访问其它存储于服务账号上的数据。
客户端验证流程
应用通过发送凭证(应用的客户端 ID 和客户端密钥)给授权服务器请求访问口令。POST 请求看起来像这样:
https://oauth.example.com/token?
grant_type=client_credentials&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
如果凭证通过了验证,授权服务器返回访问口令给应用。
访问口令使用用例
应用有了访问口令以后可能通过 API 访问可访问的用户账户信息。
一下是一个使用 curl
的 API 请求例子(注意这里包含了访问口令):
curl -X POST -H "Authorization: Bearer ACCESS_TOKEN""https://api.digitalocean.com/v2/$OBJECT"
假设访问口令有效,将以 API 文档里写的那样执行这个 API。如果访问口令没有通过验证,将返回一个『invalid_request』错误。
更新口令流程
在一个访问口令过期后,再使用它来访问 API 将收到『Incalid Token Error』。在这一点上,如果一开始获取访问口令的时候同时也返回了更新口令,更新口令可以用于请求一个新的访问口令。
以下是一个使用了更新口令的 POST 请求新访问口令例子:
https://cloud.digitalocean.com/v1/oauth/token?grant_type=refresh_token&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN
结论
现在你应该对 OAuth 2 如何工作有了很好的了解,知道何时改使用何种授权流程。
如果想学习更多关于 OAuth 2 的知识,可以看看下面这几篇文:
How To Use OAuth Authentication with DigitalOcean as a User or Developer
How To Use the DigitalOcean API v2
The OAuth 2.0 Authorization Framwork