本文是一篇关于OAuth2.0的启蒙教程,图文并茂,通俗易懂,力求用最简洁明了的方式向初学者解释OAuth2.0是什么。本文并不是冗杂难懂的长篇大论,一图胜千言,深入浅出OAuth2.0,知其然知其所以然。
参考文献
首先,需要有用户数据:
然后有个负责存储管理用户数据的资源服务器:
有个能够访问用户数据的客户端应用:
接着资源服务器会暴露出API接口,供客户端应用进行调用:
然后客户端应用可以通过这个API接口去访问用户数据:
最后资源服务器将用户数据返回给客户端应用:
如果来了个恶意客户应用怎么办:
即使恶意客户应用要求访问用户数据:
资源服务器还是返回用户数据:
因此需要一种机制来保护用户数据:
业界实践是提前给客户应用颁发一个Access Token, 它表示客户应用被授权可以访问用户数据:
访问用户数据时,给出Access Token:
资源服务器取出请求中的Access Token:
并校验Access Token确认客户应用有访问 用户数据的权限:
校验通过后,资源服务器返回用户数据:
该机制可以工作的前提是 必须提前给客户应用颁发Access Token:
那么就需要颁发Access Token的角色:
那么到底是谁来颁发Access Token呢?
授权服务器和客户应用的关系如下:
授权服务器负责生成Access Token:
并给客户应用颁发Access Token:
角色回顾:一个授权服务器,一个客户应用,一个资源服务器:
授权服务器负责生成Access Token:
并将Access Token颁发给客户应用:
客户应用带上Access Token访问用户数据:
资源服务器从请求中取出Access Token:
校验Access Token具有访问用户数据的权限:
校验Access Token具有访问用户数据的权限:
上面的流程中第一步是授权服务器生成Access Token, 在真实流程中,在颁发Token前先要征询用户同意:
首先客户应用请求Access Token:
授权服务器征询用户意见,是否将权限授予客户应用:
如果用户同意授权服务器颁发token:
授权服务器生成一个Access Token:
并将token颁发给客户应用:
注意黄色椭圆圈起来的部分:
OAuth 2.0标准化了Access Token的请求和响应部分, OAuth2.0的细节在RFC 6749(OAuth 2.0授权框架)中描述:
通过上面的描述,我们总结出了在OAuth2.0协议中存在四种角色:用户、客户端应用、资源服务器、授权服务器。你可能对这四种角色还是有点迷惑,不清楚它们之间的工作流程。没关系,下面通过一个形象化的例子来描述。
在使用 OAuth2 协议进行第三方授权登录(如使用 QQ 登录淘宝)的场景中,其四种角色之间的工作流程如图所示:
各个角色的定义如下:
- 资源拥有者(Resource Owner):
资源拥有者是指拥有某些资源(如用户数据、服务访问权限等)的用户。在淘宝登录的例子中,资源拥有者就是想要登录淘宝的用户。他们拥有访问自己淘宝账户的权限,并且可以授权第三方应用(如 QQ )来代表他们访问这些资源。 - 客户端应用(Client Application):
客户端应用是指希望获取资源访问权限的应用程序。在淘宝登录的例子中,淘宝网站或淘宝的移动应用就是客户端应用。它需要用户的授权才能访问用户的 QQ 账户信息,以便完成登录过程。 - 授权服务器(Authorization Server):
授权服务器是负责处理授权请求并颁发访问令牌(Access Token)的服务器。在 QQ 登录淘宝的场景中,QQ 的服务器就是授权服务器。当用户同意授权后,QQ 的服务器会生成一个访问令牌,并将其提供给淘宝的客户端应用。 - 资源服务器(Resource Server):
资源服务器是存储用户资源(如用户数据)的服务器,并根据访问令牌验证请求的合法性。在淘宝登录的例子中,淘宝的服务器就是资源服务器。它接收来自客户端应用的请求,验证附带的访问令牌,如果验证通过,则允许客户端应用访问用户的淘宝账户资源。
OAuth2 协议的流程:
- 用户尝试使用 QQ 登录淘宝。
- 淘宝客户端应用引导用户到 QQ 的授权服务器。
- 用户在授权服务器上确认授权,允许淘宝访问其账户信息。
- 授权服务器验证用户身份后,生成一个访问令牌并返回给淘宝客户端应用。
- 淘宝客户端应用使用这个访问令牌向资源服务器(淘宝服务器)请求用户数据。
- 资源服务器验证访问令牌的有效性,如果有效,允许客户端应用访问用户数据,完成登录过程。
在这个过程中,OAuth2 协议确保了用户数据的安全,因为用户可以直接控制哪些应用可以访问他们的数据,而不需要共享他们的用户名和密码。
在上面的第二步骤中,淘宝客户端应用是如何引导用户到 QQ 的授权服务器呢?
在OAuth 2.0授权流程中,客户端应用(在这个场景中是淘宝)需要构造一个特定的URL来引导用户到授权服务器(QQ服务器)进行授权。这个URL包含了几个关键的查询参数,它们的值大多由客户端应用自己确定,但必须符合授权服务器的要求。下面是这些参数的来源和作用:
(1)response_type
- 内容来源:由客户端应用指定。
- 作用:
response_type
参数指定了授权服务器应该返回给客户端应用的响应类型。在授权码流程中,这个值通常是code
,表示客户端应用请求一个授权码。那么授权服务器在用户授权后会返回一个授权码(Authorization Code),客户端应用随后可以携带这个授权码来请求授权服务器颁发访问令牌(Access Token)。
(2)client_id
- 内容来源:由授权服务器提供给客户端应用。
- 作用:
client_id
是客户端应用在注册时从授权服务器获取的唯一标识符。它告诉授权服务器是哪个客户端应用正在请求授权。在 OAuth 2.0 请求中,客户端应用需要提供这个标识符来证明自己的身份。
(3)redirect_uri
- 内容来源:由客户端应用指定,并且这个
redirect_uri
必须与在授权服务器注册应用时提供的redirect_uri
完全匹配。 - 作用:这是授权服务器在授权流程结束后,发送用户代理(如浏览器)回到客户端应用的地址。授权服务器将在这个URI上附加授权码或错误信息。
如何理解“客户端应用指定的这个redirect_uri
必须与在授权服务器注册应用时提供的redirect_uri
完全匹配”?
答:客户端应用在授权服务器注册时会提供一个或多个redirect_uri
,这些是客户端应用预先定义好的,授权服务器并不会自动生成这些URI。当客户端应用发起授权请求时,它会在请求中指定一个redirect_uri
,这个URI必须是在注册应用时提供给授权服务器的其中之一。也就是说在注册时客户端应用会在授权服务器中提供一堆redirect_uri
,但是在发起请求时客户端应用只会指定一个redirect_uri
,那么这个redirect_uri
就去那一堆redirect_uri
中查询,找到匹配的那个redirect_uri
即可。
可以用如下三个步骤理解:
- 注册阶段:当你在授权服务器(如QQ)上注册你的应用(比如淘宝)时,你需要提供一些信息,包括应用名称、应用类型、以及一个或多个
redirect_uri
。这些redirect_uri
是你控制的,用户在授权后将被重定向回的地址。例如,你可能提供https://taobao.com/callback作为一个redirect_uri
。 - 授权请求阶段:当你的应用请求用户的授权时,你会构造一个请求URL,包括
response_type
、client_id
、scope
等参数,以及你打算使用的redirect_uri
。这个redirect_uri
必须是你在注册应用时提供给授权服务器的地址之一。例如,你的请求可能包含redirect_uri
=https://taobao.com/callback。 - 安全匹配:授权服务器(QQ)会检查请求中的
redirect_uri
是否与你注册应用时提供的redirect_uri
之一完全匹配。如果不匹配,请求将被拒绝。这是一种安全措施,防止攻击者通过修改redirect_uri
来拦截授权码或访问令牌。
(4)scope
- 内容来源:由客户端应用指定。
- 作用:定义客户端应用请求访问的权限范围。这些权限由授权服务器预先定义,客户端应用在请求时指定希望获得的权限范围。
然后我们再继续谈引导用户到QQ授权服务器进行授权:
客户端应用(淘宝)通过将上述参数附加到授权服务器的授权端点URL上,构造一个完整的URL。然后,客户端应用将用户的浏览器重定向到这个URL。在实际操作中,这通常通过在客户端应用的UI中提供一个“使用QQ登录”的按钮来实现,当用户点击这个按钮时,客户端应用就会执行重定向操作。
举个例子:
假设淘宝客户端应用的client_id
是123456789
,注册的redirect_uri
是https://taobao.com/callback
,并且希望请求profile
和email
的权限(scope
)。淘宝客户端构造的URL可能如下:
https://graph.qq.com/oauth2.0/authorize?
response_type=code&
client_id=123456789&
redirect_uri=https%3A%2F%2Ftaobao.com%2Fcallback&
scope=profile+email
当用户访问这个URL时,他们将被引导到QQ的授权页面,页面上会显示淘宝请求的权限,并询问用户是否同意授权。如果用户同意,QQ授权服务器将用户重定向回淘宝网站的redirect_uri
,并附加一个授权码。
总结来说,response_type
、client_id
、redirect_uri
和scope
中的大部分内容是由客户端应用根据授权服务器的要求和客户端应用的需求自己生成的,除了client_id
是由授权服务器预先分配给客户端应用的。通过构造包含这些参数的URL并引导用户访问,客户端应用可以启动OAuth 2.0授权流程。
下面我们再全面完整地来阐述OAuth 2.0 工作流程(以淘宝网站使用 QQ 登录为例):
-
用户尝试使用 QQ 登录淘宝:用户在淘宝网站上点击使用 QQ 登录按钮,淘宝客户端应用发起一个请求到 QQ 授权服务器。
-
请求授权:淘宝客户端应用构造一个包含 response_type(通常是 code)、client_id、redirect_uri 和 scope 的请求,引导用户到 QQ 授权服务器进行授权。
-
用户授权:用户在 QQ 授权服务器上确认授权,同意淘宝访问其 QQ 账户的特定权限(由 scope 指定)。
-
获取授权码:用户同意后,QQ 授权服务器会生成一个授权码,并使用 redirect_uri 将用户重定向回淘宝客户端应用。授权码作为查询参数附加在重定向的 URL 上。
-
请求访问令牌:淘宝客户端应用接收到授权码后,使用 client_id 和 client_secret(客户端应用的密钥)向 QQ 授权服务器发送请求,以获取访问令牌。
-
获取访问令牌:QQ 授权服务器验证请求的合法性(包括 client_id、client_secret 和授权码),如果验证通过,会返回访问令牌给淘宝客户端应用。
-
访问资源:淘宝客户端应用使用获取到的访问令牌向淘宝资源服务器请求用户数据。资源服务器验证访问令牌的有效性后,返回用户数据。
-
用户登录成功:淘宝客户端应用使用从资源服务器获取的数据完成用户的登录过程。