[OAuth] 基础介绍
在传统的客户端服务器授权模型中, 当一个客户端需要访问被保护的资源(access-restricted resource, protected resource)时, 这个客户端需要提供 资源拥有者的凭据(Credential).
在上述的模型中,如果资源拥有者想要允许三方应用程序访问这个受保护的资源,那资源的拥有者需要将自己的凭证分享给这个三方应用。
这样就会导致如下问题和限制:
- 三方应用程序需要自己保存资源拥有者的凭证,以便将来使用。 这个凭证通常是一个明文的密码
- 服务器需要支持密码授权。
- 三方程序可以完全自由的访问用户的受保护资源,资源拥有者无法限制三方程序。
- 资源拥有者如果想要吊销某个三方程序的访问权限,只能通过修改密码的方式。
- 任何一个三方程序如果泄露了密码,那么所有数据都会泄漏,还有被这个密码所保护的其他数据。
(接下来,如果没有明确区别,第三方程序和客户端表示相同概念)
OAuth 通过引入授权层(authorization layer)来解决这些问题, 并将客户端角色与资源所有者角色进行分离。
在 OAuth 中,客户端请求访问由资源所有者控制并由资源服务器托管的资源,并被授予与资源所有者不同的凭据。
客户端使用访问令牌(Access Token)而不是资源拥有者的凭证来访问受保护的资源。
客户端使用访问令牌(Access Token)来访问资源服务器托管的受保护资源。这个访问令牌由授权服务器在资源所有者的批准下颁发给第三方客户端。
角色
Resource Owner (资源所有者)
能够授予对受保护资源访问权限的实体。
当资源所有者是个人时,也称为最终用户(end-user)。
Resource Server (资源服务器)
托管受保护资源的服务器,能够使用访问令牌来处理对受保护资源进行访问的请求。
Client (客户端)
代表资源所有者并经其授权发出受保护资源请求的应用程序。
客户端一词并不暗示任何特定的实现特征(例如,应用程序是在服务器、桌面还是其他设备上执行)。
Authorization Server (授权服务器)
该服务器能够在验证资源所有者身份并获得授权后,向客户端颁发访问令牌。
协议流程
+--------+ +---------------+| |--(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 ---| |+--------+ +---------------+Figure 1: Abstract Protocol Flow
如图所示的 OAuth 2.0 抽象流程描述了四个角色之间的交互:
(A) 客户端向资源所有者请求授权。
授权请求可以直接发送给资源所有者(如上所示),或者最好通过授权服务器作为中间媒介间接发送。
(B) 客户端会收到授权许可(Authorization Grant),该许可代表资源所有者的授权。
授权类型取决于客户端请求授权时使用的方法以及授权服务器支持的类型。
(C) 客户端通过向授权服务器进行身份验证并出示授权许可来请求访问令牌。
(D) 授权服务器对客户端进行身份验证并验证授权许可,如果有效,则颁发访问令牌。
(E) 客户端向资源服务器请求受保护的资源,并通过提供访问令牌进行身份验证。
(F) 资源服务器验证访问令牌,如果有效,则处理请求。
授权许可 (Authorization Grant)
授权许可 (Authorization Grant) 代表资源所有者对其受保护资源的授权,客户端使用该凭证获取访问令牌。
一共定义了四种授权类型: 授权码 (Authorization code), 隐式授权 (Implicit), 资源所有者密码凭证 (Resource Owner Password Credentials), 客户端凭证 (Client Credentials)
以及用于定义其他授权类型的扩展机制。
授权码 (Authorization code)
授权码的获取是通过授权服务器(authorization server)作为客户端和资源所有者之间的中介来实现的。
客户端不会直接向资源所有者请求授权,而是将资源所有者重定向至授权服务器(通过它的用户代理,通常是网页浏览器),授权服务器之后将资源所有者连同授权码一起返回给客户端。
在将资源所有者连同授权码一起重定向回客户端之前,授权服务器会先对资源所有者进行身份验证并获取授权。由于资源所有者仅通过授权服务器进行身份验证,因此客户端无法得知它的凭证。
授权码提供了一些重要的安全优势,例如能够验证客户端身份,以及将访问令牌直接传输给客户端,而无需通过资源所有者的用户代理传递,从而避免将其暴露给其他人,包括资源所有者。
隐式授权 (Implicit)
隐式授权是一种简化的授权码流程,主要针对使用 js 等脚本语言在浏览器中实现的客户端进行了优化。
在隐式流程中,客户端不会收到授权码,而是会直接得到访问令牌(这是资源所有者授权的结果)。授权类型为隐式(Implicit),因为这个授权流程中间不会颁发中间凭证(例如授权码), 也不会在后续流程中使用这些凭证来获取访问令牌。
在隐式授权流程中颁发访问令牌时,授权服务器不会对客户端进行身份验证。在一些情况下,可以通过用于向客户端传递访问令牌的重定向 URI 来验证客户端身份。访问令牌可能会暴露给资源所有者或其他有权访问资源所有者用户代理的应用程序。
隐式授权可以提高一些客户端(例如浏览器内应用程序)的响应速度和效率,因为它减少了获取访问令牌所需的往返次数。然而,应该在使用隐式授权获取便利性和损失的安全性之间进行权衡。
资源所有者密码凭证 (Resource Owner Password Credentials)
资源所有者的密码凭证(即用户名和密码) 可以直接用作授权凭证来获取访问令牌。
仅当资源所有者和客户端之间存在高度信任关系时, 并且其他授权凭证类型(例如授权码)不可用时, 才应使用此凭证。
尽管这种授权类型需要客户端直接访问资源所有者的凭证,但这些凭证只需使用一次用于获取访问令牌。
客户端凭证 (Client Credentials)
客户端凭证(或其他形式的客户端身份验证) 也可以作为一种授权许可。 适用于授权的范围局限于当前客户端控制下的受保护资源。或者已经提前与授权服务器协商好的受保护资源时。
访问令牌 (Access Token)
访问令牌是用于访问受保护资源的凭证。
它通常是一个由授权服务器颁发给客户端的一个字符串,这个字符串内容通常对于客户端来说是透明的. 其中通常包含授权的范围(scope) 和令牌的有效期。
刷新令牌 (Refresh Token)
刷新令牌也用于获取访问令牌的凭证。
刷新令牌由授权服务器颁发给客户端,用于在当前访问令牌失效或过期时获取新的访问令牌,或获取范围相同或更小的其他访问令牌(访问令牌的有效期可能更短,权限也可能少于资源所有者授权的权限)。
是否颁发刷新令牌由授权服务器自行决定。如果授权服务器颁发了刷新令牌,则会在颁发访问令牌时一并颁发。
刷新令牌和访问令牌一样:是一个由授权服务器颁发给客户端的一个字符串,这个字符串内容通常对于客户端来说是透明的.
+--------+ +---------------+| |--(A)------- Authorization Grant --------->| || | | || |<-(B)----------- Access Token -------------| || | & Refresh Token | || | | || | +----------+ | || |--(C)---- Access Token ---->| | | || | | | | || |<-(D)- Protected Resource --| Resource | | Authorization || Client | | Server | | Server || |--(E)---- Access Token ---->| | | || | | | | || |<-(F)- Invalid Token Error -| | | || | +----------+ | || | | || |--(G)----------- Refresh Token ----------->| || | | || |<-(H)----------- Access Token -------------| |+--------+ & Optional Refresh Token +---------------+Figure 2: Refreshing an Expired Access Token
整个流程包括以下步骤:
(A) 客户端通过向授权服务器进行身份验证并提交授权许可来请求访问令牌。
(B) 授权服务器对客户端进行身份验证并验证授权,如果有效,则颁发访问令牌和刷新令牌。
(C) 客户端使用访问令牌向资源服务器发出访问受保护的资源的请求。
(D) 资源服务器验证访问令牌,如果有效,则处理请求。
(E) 重复执行步骤 (C) 和 (D) , 直到访问令牌过期。如果客户端知道访问令牌已过期,则跳至步骤 (G);否则,它将再次发出受保护资源请求。
(F) 由于访问令牌无效,资源服务器返回无效令牌错误。
(G) 客户端通过向授权服务器进行身份验证并提供刷新令牌来请求新的访问令牌。客户端身份验证的要求取决于客户端类型和授权服务器策略。
(H) 授权服务器对客户端进行身份验证并验证刷新令牌,如果有效,则颁发新的访问令牌(以及, 可选的, 新的刷新令牌).