您当前的位置:首页 > 电脑百科 > 网络技术 > 网络知识

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

时间:2020-07-12 11:31:34  来源:  作者:

从事互联网开发的同学们应该或多或少听说过 OAuth2.0 协议,例如使用微信或支付宝账户登录第三方App,这是 OAuth2.0 最为开发人员所熟知的一个用途,但是围绕着 OAuth2.0 协议其实还有很多有意思的内容可以挖掘,我们可以用它以及它的扩展协议来做许多有用的东西。因此我打算写一个系列来详细介绍 OAuth2.0 以及围绕它所产生的一些扩展协议和优良实践。

如果你正想要设计一个基于 OAuth2.0 协议的授权服务架构来对外提供一些资源或服务,那么本系列文章将有助于你实现这一目标。

本文是本系列的第一篇,我会比较详细地带你解读 OAuth2.0 协议。本文会从基础概念和术语开始讲起,让你逐渐了解 OAuth2.0 的核心理念以及它所要解决的问题,然后将会用一多半的篇幅来详细阐述4大流程模式中使用最广的授权码模式,我会介绍它的流程、接口、错误处理、注意事项等。

注:本文涉及到 OAuth2.0 协议的所有内容全部来自于 RFC 6749 The OAuth 2.0 Authorization Framework ,也就是说全部都是第一手的解读。

什么是授权、授权认证、资源外放?

什么是授权?要解释这个问题,先要引入一个概念——资源。信息或者数据就是一种资源,例如用户的身份信息、用户的相册数据、评论记录、收藏的网站等等,除了信息或数据之外,完成某项特定操作的能力也是一种资源,通常以API的形式出现,例如发送短信、上传头像、发布vlog等等,这些都是API也是资源。有些资源需要用户的授权(如获得用户身份信息),而另一些资源不需要得到用户的授权(如发送短信),我们今天所讨论的,是需要用户授权的那一类——毕竟这些资源的所有权属于用户。

在什么时候需要授权呢?我们来假设一个场景,我们大部分开发者都有Github账号(假装大家都有),但是由于某些原因,Github以前并不提供移动版的官方客户端,但广大群众需要在移动端使用Github的呼声很强烈,这怎么办呢?Github的做法是,虽然我不提供官方的app,但是我提供用于管理用户资源的APIs,这些APIs包含了用户认证信息(user)、仓库(repositories)、订阅者(followers)、已订阅(following)、星标(starred)记录等等几乎全部的数据,这样就可以吸引那些热心的开发者为他编写非官方的客户端程序,或者其它有用的应用。那么是不是所有人或程序都能毫无限制的去使用这些 APIs 呢?显然是不可以的,那么Github就需要通过某种机制来保护这些APIs,使得调用者必须要在用户的允许(consent)之下才能够进行调用。那么授权的含义就很容易理解了——即调用者(client)获取用户的“允许”以访问用户的数据的过程就称为“授权”。

我们现在明白什么是授权了,那么授权认证是什么意思呢?授权认证其实就是授权当中的一类特殊情况,即调用者(client)所要申请访问的资源属于用户身份信息(或称为认证信息)且调用者(client)使用此资源的目的在于帮助其(client)对用户进行认证时,这种特殊的授权行为又称为授权认证。

什么是资源外放?在上文中,Github网站提供了用于访问用户数据的API的行为就属于资源外放。资源外放通常要搭配授权协议一起实施。


什么是授权协议、OAuth2.0?

什么是协议?协议就是标准,就是一套规则体系。上文中,用于规定授权操作的流程、接口、错误处理方式等等规则的集合,就是一个授权协议。目前互联网上使用最广的授权协议是OAuth2.0。

OAuth2.0是由IETF(互联网工程小组)编纂并维护的一套授权协议,是目前业界的事实标准。

国内的微信、支付宝,国外的微软、谷歌等等巨头,都采用了此协议来对外提供API资源。

在这里我有必要强调一点,OAuth2.0 并不是一个认证协议,它不是被设计为解决认证问题的,如果你希望设计一个认证架构,那么你应该考虑 OpenID Connect (OIDC) 协议,它是 OAuth2.0 的衍生协议,由 OpenID 发起并维护,目前已得到很多大型互联网公司的支持,例如谷歌、微软、苹果、亚马逊。而如果你要学习 OIDC 协议,那么我建议你也应该从 OAuth2.0 协议开始。

OAuth2.0 关键概念和术语

从这一段开始,我们来正式讲解 OAuth2 协议,首先来介绍一下此协议有哪些重要的概念或术语。

Resource Owner

资源拥有者,即用户

Resource Server

资源服务器,即存储用户资源的服务器,通常以 API 的形式暴露服务,它会在验证 Access Token 通过后为调用者提供用户资源

Client

客户端,即申请用户授权的主体,可以是前端程序 —— 如 JAVAScript 应用、移动端原生 App 等等,也可以是服务器端应用程序 —— 如 Java 程序

Authorization Server

授权服务器(签发授权码和访问令牌)

Access Token

访问令牌,拿到此令牌即可访问 Resource Server 中的用户资源

Refresh Token

刷新令牌,用来获得新的 Access Token ,有时 Authorization Server 会在签发 Access Token 的同时也附加一个 Refresh Token ,这样 Client 就不必每次都去询问用户获得授权了

Client Type

客户端类型,分为 Public 和 Confidential 两种

Client Identifier

客户端标识,即 client_id ,唯一标识一个 Client

Client Authentication

客户端认证,对 Public 类型的 Client 采用 PKCE 的方式认证,而对 Confidential 类型的 Client 一般会采用 Basic 方式或基于非对称算法的 JWT 方式来进行认证。

OAuth2.0 基本流程

尽管网络上很多作者都会直接开始讲解授权码模式的流程图,但我认为还是有必要先了解 OAuth2.0 最最基本的抽象流程图,它是所有具体流程模式的抽象概括版,可以让我们跳出具体的流程模式并站在一定高度上来审视 OAuth2.0 协议究竟是什么,解决了哪些问题,对于你理解一些关于 OAuth2.0 的误区是有帮助的,如下图:

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

OAuth2.0 抽象流程图

图片来自 RFC6749 - The OAuth 2.0 Authorization Framework

上图展现了 OAuth2.0 协议的本质,它概括为3个步骤:申请授权、获得授权、访问资源。 OAuth2.0 的所有流程模式(除了早先的四大模式之外还有谷歌的设备码模式)都是这3个步骤的具体表现形式。

网络上很多教程会一上来就给你看授权码模式的流程图,而我必须要说明一点,授权码模式不等同于 OAuth2.0 协议的全部,尽管该模式的确是使用最多的一种流程模式,但它只是一种流程模式,不是此协议的本质。

如果跳过上面的抽象流程图而直接开始讲授权码模式、简化模式等流程模式,那么有一个很大的坏处就是,它会使你误认为 OAuth2.0 是一个认证协议,因为授权码模式(还有简化模式)中带有认证过程,即 Authorization Server 会对 User 进行认证,认证之后才会有授权码 code 和 Access Token ,这会让你误以为拿到 code 或 Access Token 就代表用户已得到认证,你就可以拿到用户的身份信息了,但在抽象流程图中并没有出现“认证 Authentication”的字眼。Access Token 压根就不是一个表示认证信息的令牌,它是一个授权令牌,它只能表示一个 Client 确实获得了某用户的某项资源的访问权限,但这既不能体现用户的登录状态,亦不表示一定能够获得用户的身份信息,例如使用 Refresh Token 就可以刷新得到一个新的 Access Token ,而这个过程是不需要用户参与的。


授权码模式 Authorization Code

基本流程

授权码模式是应用最广泛的一种流程模式,它可以应用于任何有 Web 支持的平台,例如传统 Web 网站,单页应用 SPA ,移动端原生 App 等等,它的流程图如下:

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

OAuth2.0 授权码模式流程图

分步骤讲解:

A) 客户端程序( Client )向资源拥有者( Resource Owner )申请授权,并指定一个回跳地址用于接收接下来所产生的授权码或错误信息

B) 资源拥有者同意授权,并返回一个凭证给客户端程序,这个凭证就是授权码 code

C) 客户端程序拿到授权凭证(即授权码 code )后向授权服务器(Authorization Server)申请 Access Token

D) 授权服务器验证客户端程序提供的授权凭证后返回 Access Token 给到客户端 Client

E) 客户端程序 Client 使用 Access Token 访问资源服务器(Resource Server)中的用户资源

F) 资源服务器验证 Access Token 后返回受保护的资源

以上描述中注意客户端程序并不是指 C-S 架构下的 Client 客户端,它在这里既可以指前端程序(如 SPA 或 APP ),也可以指WEB网站的后台服务器(如 Java Web 应用)

在授权码模式中,我们可以看到 Authorization Server 提供了2个接口( Endpoint ),即申请授权接口与获得授权令牌接口,对应的分别是申请授权与获得授权这两个步骤。下面我们来详细看一下这两个接口都定义了哪些内容以及它们的使用方法。

注意:OAuth2.0 及其扩展协议中所涉及的所有接口( Endpoint )全部都是 HTTP 接口

申请授权接口 Authorization Endpoint

申请授权接口的请求 Authorization Request

首先,Client 需要先构建一个用于跳转的 uri 地址,这个地址是由 Authorization Server 即授权服务器提供的,Client 需要在它的后面拼接如下这些参数(使用 application/x-www-form-urlencoded 编码方式对参数进行编码):

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

申请授权接口的请求参数

然后 Client 要控制用户的 User-Agent (一般就是浏览器)跳转到刚刚构建的 uri 上去,下面是一个例子:

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

申请授权接口的请求例子

在此接口中,有如下几点规则需要注意:

  • 注意以上参数是拼接在 uri 后面的,不是在 http body 中的,编码格式是 application/x-www-form-urlencoded
  • 授权服务器 Authorization Server 收到请求后,应验证该请求是否正确,例如 client_id 是否存在, redirect_uri 是否合法等等
  • 如果请求正确,则授权服务器 Authorization Server 需要先认证用户(如果有必要)并询问用户以获得用户的授权决定 authorization decision ,一般常见的方式就是显示一个授权页面,用户可以同意授权,也可以拒绝授权
  • 当用户做出授权选择后,授权服务器 Authorization Server 应当控制 User-Agent (浏览器)去跳转到前面参数中的 redirect_uri 中,如果用户选择了同意授权,那么跳转地址后面要附带授权码 code 和随机数 state (如果请求中有),关于这两个参数请参见下面的表格“申请授权接口的响应参数(同意授权的情况)”
  • 如果用户拒绝授权,或者授权过程出现了错误,则授权服务器应当参照下面的错误处理方式来处理,关于相关参数和错误代码值请参见下面的表格“申请授权接口的响应参数(授权失败的情况)”
  • 请特别留意一下 state 这个参数,它可以用来防止 CSRF 攻击,具体的攻击方式本文就不介绍了,你可以自行搜索。state 参数是由 client 生成,最终由 client 完成校验的。在本接口处理完成后(不论是成功或发生错误),在重定向回 redirect_uri 的时候应当带上 state 参数(如果有就必须带上)。
  • 控制 User-Agent 跳转的方式可以是 302 重定向,也可以是其他方法,比如 JavaScript 跳转等

申请授权接口的响应(授权成功的情况) Authorization Response

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

申请授权接口的响应参数(同意授权的情况)


你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

申请授权接口的响应例子(同意授权的情况)

申请授权接口的响应(授权失败的情况) Authorization Error Response

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

申请授权接口的响应参数(授权失败的情况)


你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

申请授权接口的错误代码值


你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

申请授权接口的响应例子(授权失败的情况)

很多人在实现 OAuth2.0 的过程中往往会忽视对于错误情况的处理,其实 OAuth2.0 已经规定了错误处理方式了,如果你的目标是要建立一个标准的 OAuth2.0 服务,那么别忽视错误处理这一环。

返回错误信息时要特别注意的几点

  • 每个 client 在注册时应指定它所能使用的 redirect_uri ,Authorization Server 应保存下来这些 redirect_uri ,并在本接口被调用时验证 client_id 与 redirect_uri 是否匹配,以此来避免恶意攻击。
  • 如果 redirect_uri 与 client_id 匹配,则依据上图把相应的错误信息拼接在给定的回跳地址 redirect_uri ,并控制 User-Agent 重定向到该地址;
  • 但如果 redirect_uri 与 client_id 不匹配,或者违反了黑名单或白名单的规则(这个规则是你可以自己设计的),那么不应该做跳转,而应当在授权服务器上给予适当提示。
  • 只要 redirect_uri 没有问题,那么所有类型的错误,都应该发送给 client ,让 client 能够感知到错误的发生,并依据错误类型给用户良好的错误信息展示,而不是由 Authorization Server 去显示这些错误。

获取访问令牌接口 Access Token Endpoint

获取访问令牌接口的请求 Access Token Request

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

获取访问令牌接口的请求参数


你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

获取访问令牌接口的请求例子

注意:在请求中,注意编码格式 Content-Type 是 application/x-www-form-urlencoded ,并且 method 是 POST ,这与下面的响应是不一样的。

在此接口中,授权服务器 Authorization Server 必须满足以下几点:

  • 授权服务器必须对 Client 进行认证,Confidential 类型的 Client 可以采用 Basic 方式来认证,关于 Basic 认证方式请自行搜索一下;当然也可以使用基于非对称加密算法的 JWT 令牌来认证;而 Public 类型的 Client 如果要使用此接口,则必须实现 PKCE 协议,关于 PKCE 我会在以后的文章中专门讨论,你也可以自行搜索一下
  • 授权服务器必须确保请求参数中的 code 和 client_id 是匹配的,换句话说, code 确实是签发给请求中的 client_id 的
  • 确保 code 是有效的,有效包含2层含义 —— code 确实是授权服务器签发的、code 仍在有效期内
  • 如果前面的“申请授权接口的请求 Authorization Request”中有 redirect_uri ,那么本接口中也应当包含 redirect_uri ,并且值必须是一致的。这一点在很多其它博客上很容易忽视,但它很重要

获取访问令牌接口的响应

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

获取访问令牌接口的响应参数(成功的情况)

注意, expires_in 的单位是秒,如果你不返回此参数,则应当与 Client 约定一个默认值,并在文档中注明。

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

获取访问令牌接口的响应例子(成功的情况)

关于获取访问令牌接口的响应,有以下几点要注意:

  • 返回的参数必须以 JSON 格式放到 HTTP Response Entity-Body 中,也就是报文体中,Content-Type 必须是 application/json (后面的字符集可以加上也可以不加上)
  • 上面参数表中定义的参数必须放在 JSON 结构的最顶层,换句话说就是不要搞嵌套
  • 除了上面表格中规定的参数,你可以附加别的参数

上面是授权成功的情况,那么授权失败的情况呢?

你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

获取访问令牌接口的响应参数(失败的情况)


你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

获取访问令牌接口的错误代码值


你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议

获取访问令牌接口的响应例子(错误的情况)

关于本接口在错误情况下的响应,有以下几点要注意:

  • 在错误情况下,本接口依然要以 JSON 的格式来返回错误信息,即 Content-Type 是 application/json (后面的字符集可以加上也可以不加上)
  • HTTP Status 状态码是 400 ,注意不是 200 ;我知道很多开发者习惯于不论什么情况,都返回 200 ,然后在 HTTP Response Entity-Body 中的 JSON 报文里添加一个状态字段,但在本接口里,是通过 HTTP Status 来表达错误的,请一定注意这一点

现在 Client 获得了 Access Token 之后,就可以去访问受保护资源了,而 Resource Server 要如何校验 Access Token 呢?其实这一点最开始 ITEF 并没有归纳到协议中,而是通过另外一个协议来将此内容补充上了,请参见 RFC 7662 - OAuth 2.0 Token Introspection

结语

至此,我们已经介绍完了 OAuth2.0 协议的基础知识和授权码模式,其实 OAuth2.0 协议还有非常多值得挖掘的细节,以及很多扩展或衍生协议,来帮助你在各种不同的平台上使用这个协议来完成授权或授权认证的工作,我会在其它文章中陆续为大家解读 OAuth2.0 协议的方方面面。

如果本文中有哪些地方你没有读懂,或希望重点展开的,欢迎给我留言。另外如果你发现本文存在纰漏,也欢迎随时给我留言,共同学习。



Tags:OAuth2.0   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
最开始接触 OAuth2.0 的时候,经常将它和 SSO单点登录搞混。后来因为工作需要,在项目中实现了一套SSO,通过对SSO的逐渐了解,也把它和OAuth2.0区分开了。所以当时自己也整理了一篇...【详细内容】
2021-09-16  Tags: OAuth2.0  点击:(68)  评论:(0)  加入收藏
介绍OAuth(开放授权)是一个开放标准,允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方应用或分享他们数据的所有内容。OAuth...【详细内容】
2020-08-18  Tags: OAuth2.0  点击:(65)  评论:(0)  加入收藏
从事互联网开发的同学们应该或多或少听说过 OAuth2.0 协议,例如使用微信或支付宝账户登录第三方App,这是 OAuth2.0 最为开发人员所熟知的一个用途,但是围绕着 OAuth2.0 协议其...【详细内容】
2020-07-12  Tags: OAuth2.0  点击:(102)  评论:(0)  加入收藏
一、什么是OAuth协议OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 OAuth的授权不会使第三方触及到用户的帐号信息(如用户...【详细内容】
2019-08-01  Tags: OAuth2.0  点击:(272)  评论:(0)  加入收藏
▌简易百科推荐
以京训钉开发平台接口文档为例,使用HttpClient类请求调用其接口,对数据进行增删改查等操作。 文档地址: https://www.yuque.com/bjjnts/jxd/bo1oszusing System;using System.C...【详细内容】
2021-12-28  Wednes    Tags:HttpClient   点击:(1)  评论:(0)  加入收藏
阿里云与爱快路由安装组网教程一、开通好阿里云轻量服务器之后在服务器运维-远程连接处进行远程 二、进入控制台后在root权限下根据需要安装的固件位数复制下面命令。32位:wg...【详细内容】
2021-12-28  ikuai    Tags:组网   点击:(1)  评论:(0)  加入收藏
HTTP 报文是在应用程序之间发送的数据块,这些数据块将通过以文本形式的元信息开头,用于 HTTP 协议交互。请求端(客户端)的 HTTP 报文叫做请求报文,响应端(服务器端)的叫做响应...【详细内容】
2021-12-27  程序员蛋蛋    Tags:HTTP 报文   点击:(4)  评论:(0)  加入收藏
一 网络概念:1.带宽: 标识网卡的最大传输速率,单位为 b/s,比如 1Gbps,10Gbps,相当于马路多宽2.吞吐量: 单位时间内传输数据量大小单位为 b/s 或 B/s ,吞吐量/带宽,就是网络的使用率...【详细内容】
2021-12-27  码农世界    Tags:网络   点击:(3)  评论:(0)  加入收藏
1.TCP/IP 网络模型有几层?分别有什么用? TCP/IP网络模型总共有五层 1.应用层:我们能接触到的就是应用层了,手机,电脑这些这些设备都属于应用层。 2.传输层:就是为应用层提供网络...【详细内容】
2021-12-22  憨猪哥08    Tags:TCP/IP   点击:(35)  评论:(0)  加入收藏
TCP握手的时候维护的队列 半连接队列(SYN队列) 全连接队列(accepted队列)半连接队列是什么?服务器收到客户端SYN数据包后,Linux内核会把该连接存储到半连接队列中,并响应SYN+ACK报...【详细内容】
2021-12-21  DifferentJava    Tags:TCP   点击:(10)  评论:(0)  加入收藏
你好,这里是科技前哨。 随着“元宇宙”概念的爆火,下一代互联网即将到来,也成了互联网前沿热议的话题,12月9日美国众议院的听证会上,共和党议员Patrick McHenry甚至宣称,要调整现...【详细内容】
2021-12-17  王煜全    Tags:Web3   点击:(14)  评论:(0)  加入收藏
一、demopublic static void main(String[] args) throws Exception { RetryPolicy retryPolicy = new ExponentialBackoffRetry( 1000, 3);...【详细内容】
2021-12-15  程序员阿龙    Tags:Curator   点击:(22)  评论:(0)  加入收藏
一、计算机网络概述 1.1 计算机网络的分类按照网络的作用范围:广域网(WAN)、城域网(MAN)、局域网(LAN);按照网络使用者:公用网络、专用网络。1.2 计算机网络的层次结构 TCP/IP四层模...【详细内容】
2021-12-14  一口Linux    Tags:网络知识   点击:(31)  评论:(0)  加入收藏
无论是在外面还是在家里,许多人都习惯了用手机连接 WiFi 进行上网。不知道大家有没有遇到过这样一种情况, 明明已经显示成功连接 WiFi,却仍然提示“网络不可用”或“不可上网”...【详细内容】
2021-12-14  UGREEN绿联    Tags:WiFi   点击:(25)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条