OAuth 2 学习记录

1. 基本概念

 OAuth 2.0 授权框架可以让第三方应用程序获取Http服务有限的访问权限,传统客户端模型中,客户端在请求访问受限资源服务器时,需要使用资源所有者(用户)通过认证服务器进行授权,但是这样的方式是有一些缺陷的:

  • 需要使用第三方应用程序来存储资源,所有者的凭据以提供将来使用,通常是密码明文;
  • 服务器支持用户名、密码的验证方式,但很不推荐,除非在其他方式不可用的情况下;
  • 第三方应用程序获得对资源的过度访问,使得资源所有者没有任何能限制第三方应用访问资源的持续时间或有限的子集资源;
  • 资源所有者无法撤销对单个第三方应用的访问权限,如果想这么干,唯一的办法就是修改密码才能限制;
  • 任何第三方应用程序的妥协都会导致泄密,同时所有受该密码保护的所有数据也将泄露;

 OAuth 通过引入一个授权层将第三方应用和资源所有者分离开解决了这些问题,在OAuth 框架中,客户端对资源的访问请求是由资源所有者和托管资源的服务器所控制的,并且是发布了一组不同于资源的凭据所有者。

下面有几个关于不同角色的基本概念:

  • Third-party application:第三方应用程序,即客户端(client);
  • HTTP service:HTTP服务提供商,简称服务提供商,比如谷歌;
  • Resource Owner:资源所有者,即拥有共享资源的人(常见)或应用;
  • User Agent:用户代理,即指浏览器;
  • Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器;
  • Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器,它与认证服务器,可以是同一台服务器,也可以是不同的服务器;

OAuth的作用就是让"客户端"安全可控地获取"用户"的授权,与"服务商提供商"进行互动,大概的协议流程如下:

 +--------+                               +---------------+
 |        |--(A)- Authorization Request ->|   Resource    |
 |        |                               |     Owner     |
 |        |<-(B)-- Authorization Grant ---|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(C)-- Authorization Grant -->| Authorization |
 | Client |                               |     Server    |
 |        |<-(D)----- Access Token -------|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(E)----- Access Token ------>|    Resource   |
 |        |                               |     Server    |
 |        |<-(F)--- Protected Resource ---|               |
 +--------+                               +---------------+

2. 客户端类型

 OAuth 2.0 规范中定义了两种客户端类型:

  • 保密类型(confidential):可以对外保持客户端保密,该客户端密码是由授权服务器分配给客户端应用的,为了避免欺骗,这个密码可以用来识别客户端(比如保密的客户端是一个WEB应用,那除了管理员没有人可以访问服务器或看到该密码);
  • 公开类型(public):不能使客户端密码保密,如以手机APP或桌面App将密码嵌在内部,这些App都有可能被破解随之泄露密码。

 OAuth 2.0 规范也提到一些客户端的配置文件,这些配置文件是具体类型的应用程序,可以是保密的或公开的,配置文件有:

  • Web应用:即运行在WEB服务器内的应用,如果Web应用访问资源服务器,然后客户端密码被保存在服务器上,因此密码是保密的;
  • 用户代理:如运行在浏览器上的JS应用,浏览器是用户代理,用户代理可以保存在Web服务器上,但应用程序之运行一次下载的用户代理;
  • 原生:如桌面App或手机App,原生应用典型的被安装在PC或其他设备上,因此客户端的密码也被存储在用户的设备上;

3. 授权

 客户端想要访问资源所有者托管在资源服务器上的资源时,用户必须要对客户端进行授权后才能让它去访问资源服务器上的资源,在客户端访问资源服务器时,必须先在资源服务器相关联的授权服务器中进行注册。注册一个一次性的任务,一旦注册了,除非客户端注册被取消,否则注册持续有效。注册后将由授权服务器分配客户端标识和密钥,在授权服务器上,客户端标识和密钥是唯一标识客户端应用的,如果客户端应用注册了多个授权服务器,每个授权服务器将发出唯一的标识给该客户端应用,客户端需要将客户端标识和密钥发送到授权服务器验证通过后才能访问资源,在注册时,客户端应用也注册了一个重定向URI,当资源拥有者成功的通过授权服务器授权给客户端应用时,资源拥有者被重定向回到客户端应用,再跳转到该重定向URI。

 授权比准由资源服务器和授权服务器给客户端应用的,OAuth 2.0 中定义了四种不同类型的授权批准:

  • 授权码(Authorization Code);
  • 隐式授权(Implicit);
  • 密码凭证(Resource Owner Password Credentials);
  • 客户端凭证(Client Credentials);

3.1 授权码

 授权码实际是作为从授权服务器获取的客户端和资源所有者之间的媒介,通过授权码的授权方式,资源拥有者的凭证不会和第三方共享。通过授权码进行授权的工作流程大致如下:

  1. 资源拥有者(用户)访问客户端应用;
  2. 客户端应用告诉用户通过授权服务器(如Facebook, Google和Twitter等)登录到客户端应用;
  3. 为了通过授权服务器登录,用户通过客户端应用被重定向到授权服务器,客户端应用发送它的客户端标识给授权服务器,那么授权服务器就知道是哪个应用尝试访问受保护的资源了;
  4. 当被重定向回客户端应用时,授权服务器发送给用户特定的重定向URI, 即客户端已经提前在授权服务器上进行注册了,随着重定向,授权服务器发送一个代表授权的授权码;
  5. 当在客户端应用的重定向URI被访问时,客户端应用直接连接授权服务器,客户端应用发送授权码,客户端标识及密钥;
  6. 如果客户端应用能接受这些值,那么授权服务器返回一个访问令牌;
  7. 客户端应用就可以用该访问令牌请求资源服务器上的资源了,令牌就是客户端被授权和访问资源的凭证。

通过授权码授权的流程如下:
授权码授权流程

 稍微理一理可以发现,授权码授权过程中主要存在2对请求、响应,一对是客户端向认证服务器(或授权服务器)请求授权的请求、响应,另一对是客户端向认证服务器请求令牌的请求、响应。

3.1.1 客户端向认证服务器请求授权的请求以及认证服务器向客户端做出的响应

1.客户端向认证服务器请求授权

 在请求授权的过程中,主要参数有:其中客户端使用客户端标识符和重定向的URI向认证服务器申请认证时,URI应该包含下面的一些参数:

  • response_type:表示授权类型,授权码的授权方式中该变量值为code
  • client_id:表示客户端的ID,在客户端被注册时,授权服务器需要用该参数标记客户端;
  • redirect_uri:表示重定向的URI(可选);
  • scope:表示申请的权限范围(可选);
  • state:表示客户端的当前状态,可指定为任意值,认证服务器会原封不动地返回这个值(可选,推荐使用)。

下面是一个小栗子(w3cshool通过QQ登录被重定向到QQ的认证服务器的授权页面,状态码为302):

https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=101348312&redirect_uri=https://www.w3cschool.cn/callback&state=bf63b1f5205547e2746dc4a8ac262aa7&scope=get_user_info

# 除了上述的url外,还有看到下面一个url,有点像
https://graph.qq.com/oauth2.0/show?which=Login&display=pc&response_type=code&client_id=101348312&redirect_uri=https://www.w3cschool.cn/callback&state=bf63b1f5205547e2746dc4a8ac262aa7&scope=get_user_info

2.认证服务器回应客户端请求授权的响应

 在认证服务器带着AuthCode重定向到客户端的URI时,会包含下面的参数:

  • code:表示授权码,一般授权码的有效期很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
  • state:如果客户端请求授权的请求中包含这个参数,那认证服务器的回应也必须一模一样包含这个参数,

同样以上述w3cschool中的在重定向到QQ的认证服务器后,用户点击QQ头像进行授权的行为为例,看一下授权后跳转的路径(包含codestate参数):

https://www.w3cschool.cn/callback?code=6432B7F3B61AAD3660E16C4AC54574AD&state=bf63b1f5205547e2746dc4a8ac262aa7

上面是授权成功后返回的结果,那当然也会出现授权不成功的情况,在授权不成功的情况下,也会将一些信息带回给客户端:

  • error:必须是预定义的错误码之一,详细情况需要具体查看;
  • error_description:可选参数,是一段UTF-8编码的描述错误的文本,适用于开发者,而不是最终用户;
  • error_uri:可选参数,指向包含人类可读的错误信息网页的URI;
  • state:如果出现在授权请求期间,必须请求中的state参数一样;
3.1.2 客户端向认证服务器请求令牌的请求以及认证服务器向客户端做出的响应

1.客户端向认证服务器请求令牌

 客户端通过之前获取的 Auth Code 重定向到URI认证服务器请求认证时(即获取Access Token的请求),请求的URL通常包含下面一些参数:

  • grant_type:表示使用的授权模式,授权码的授权方式中该参数的值为authorization_code
  • code:表示上一步获得的授权码;
  • redirect_uri:表示重定向的URI,且必须和客户端将用户重定向到服务提供商的认证服务器那一步中的该参数值保持一致;
  • client_id:表示客户端ID;(这个参数未知)

下面是一个小栗子(未测试抓到该结果):

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

2.认证服务器回应客户端请求令牌的请求

 认证服务器对客户端认证通过后返回 Access Token 时,认证服务器返回的响应应该包含下面的一些参数:

  • access_token:表示授权服务器分配的访问令牌;
  • token_type:表示授权服务器分配访问令牌的类型,该值大小写不敏感,可以是bearer类型或mac类型;
  • expires_in:表示访问令牌的过期时间,单位为秒,如果省略该参数,在其他方式中必须设置过期时间;
  • refresh_token:表示令牌过期后刷新的令牌,用于获取下一次的访问令牌(可选);
  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略;

下面是一个小栗子(测试未抓取到结果):

     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

上述相关的代码,相关参数使用JSON格式发送(Content-Type:application/json),此外,HTTP的Header信息中明确指定不得缓存(即Cache-Control: no-store)。

3.2 隐式授权

 隐式授权感觉好像就是简化的授权码授权方式,在上述授权码的工作流程图中的第4步中,伴随着重定向回客户端指定的URI后外一起返回的不再是AuthCode了,而是直接返回Access Token,随后用户直接使用令牌去访问重定向的URI,最后登录成功即可。令牌可以被用户代理访问,或在隐式授权过程中参与的原生应用,令牌在Web服务器上不是安全存储的。

 在隐式授权方式中,主要包含一对请求、响应,即客户端向授权服务器请求令牌的请求与响应。

1.客户端向认证服务器请求令牌

用户在被客户端重定向到认证服务器时,客户端向认证服务器发送的请求会包含下面的参数:

  • response_type:表示授权类型,隐式授权方式中该参数的值为token
  • client_id:表示客户端的ID,在客户端被注册时,授权服务器需要用该参数标记客户端;
  • redirect_uri:表示重定向的URI(可选);
  • scope:表示权限范围(可选);
  • state:表示客户端的当前状态,可以指定为任意值,认证服务器会原封不动地返回这个值(可选,推荐);

下面是一个小栗子:

GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com

2.认证服务器回应客户端请求令牌的请求

在认证服务器带着 Access Token 向客户端重定向时,注意这里的响应不是JSON,认证服务器回给客户端的URI会包含下面的一些参数:

  • access_token:表示授权服务器分配的访问令牌;
  • token_type:表示授权服务器分配访问令牌的类型,该值大小写不敏感,可以是bearer类型或mac类型;
  • expires_in:表示访问令牌的过期时间,单位为秒,如果省略该参数,在其他方式中必须设置过期时间;
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略;

下面是个小栗子:

HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600

当然,上述是成功授权的情况,也会出现授权不成功的情况,不成功时响应给客户端的和授权码方式授权失败的返回格式一致,包含:

  • error:必须是预定义的错误码之一,详细情况需要具体查看;
  • error_description:可选参数,是一段UTF-8编码的描述错误的文本,适用于开发者,而不是最终用户;
  • error_uri:可选参数,指向包含人类可读的错误信息网页的URI;
  • state:如果出现在授权请求期间,必须请求中的state参数一样;

3.3 密码凭证

 资源拥有者直接在客户端输入用户在资源服务器上的用户名和密码,客户端就可以使用这些信息向服务商索要授权,然后访问到用户的在资源服务器上的资源,这种方式不推荐使用,通常用于用户代理或原生应用中,因为用户必须将自己的用户名、密码给客户端,这种方式可能导致第三方应用会滥用用户的资源。

 密码凭证的授权方式很简单:

  1. 用户向客户端提供用户名和密码;
  2. 客户端将用户名和密码发给认证服务器,向后者请求令牌;
  3. 认证服务器确认无误后,向客户端提供访问令牌;

 在密码凭证授权方式中,主要包含一对请求、响应,也是客户端向授权服务器请求令牌的请求与响应。

1.客户端向认证服务器请求令牌

 客户端利用用户的用户名、密码去认证服务器请求令牌时,发送的请求会包含下面一些参数:

  • grant_type:表示授权类型,在密码凭证授权方式中,该参数的值为password
  • username:表示用户名,UTF-8编码;
  • password:表示用户的密码,UTF-8编码;
  • scope:表示权限范围(可选);

下面是个小栗子:

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

2.认证服务器回应客户端请求令牌的请求

 在认证服务器响应客户端请求令牌时,会包含下面一些参数:

  • access_token:表示授权服务器分配的访问令牌;
  • token_type:表示授权服务器分配访问令牌的类型,该值大小写不敏感,可以是bearer类型或mac类型;
  • expires_in:表示访问令牌的过期时间,单位为秒,如果省略该参数,在其他方式中必须设置过期时间(可选);
  • refresh_token:表示令牌过期后刷新的令牌,用于获取下一次的访问令牌(可选);

小栗子如下:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}

3.4 客户端凭证

 使用自己客户端的名义,而不是用户的名义,向“服务提供商”进行认证,严格说,客户端认证模式并不属于OAuth框架所要解决的问题,用户直接向客户端注册,客户端以自己的名义要求“服务提供商”提供服务,不存在授权问题,主要流程为:

  1. 客户端向认证服务器进行身份认证,并要求一个访问令牌;
  2. 认证服务器确认无误后,向客户端提供访问令牌;

 在客户端凭证授权方式中,主要包含一对请求、响应,也是客户端向授权服务器请求令牌的请求与响应。

1.客户端向认证服务器请求令牌

 客户端向认证服务器请求令牌时,HTTP请求中应该包含下面一些参数:

  • granttype:表示授权类型,在客户端凭证授权方式中该参数的值为clientcredentials
  • scope:表示权限范围(可选);

比如下面的请求URL:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

2.认证服务器回应客户端请求令牌的请求

 认证服务器必须以某种方式验证客户端的身份,在响应客户端的请求时,返回的数据会包含下面一些参数:

  • access_token:表示授权服务器分配的访问令牌;
  • token_type:表示授权服务器分配访问令牌的类型,该值大小写不敏感,可以是bearer类型或mac类型;
  • expires_in:表示访问令牌的过期时间,单位为秒,如果省略该参数,在其他方式中必须设置过期时间(可选);

比如:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}

在整个授权过程中,不论是哪种授权方式,都会遇到更新令牌的问题,即客户端的访问令牌过期了,客户端需要发出更新令牌的请求,请求中会包含下面的一些参数:

  • granttype:表示使用的授权模式,更新令牌时该参数值为refreshtoken
  • refresh_token:表示之前收到的更新令牌;
  • scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致;

4. OAuth 2.0 中的端点

 在OAuth 2.0 中定义了一系列的端点,包含了:

  • 授权端点(Authorization Endpoint):是资源拥有者所登录的授权服务器,并授权给客户端应用的端点;
  • 令牌端点(Token Endpoint):在授权服务器上为了一个访问令牌,客户端应用要交换授权码,客户端标识和客户端密钥的端点;
  • 重定向端点(Redirect Endpoint):在授权端点授权以后,资源拥有者被重定向到客户端应用的端点;

如果用上一章的授权工作流图可以做如下端点标记:

端点分布图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值