OAuth 全称 Open Authorization 中文翻译开放授权;是一种基于令牌的身份验证,允许组织跨第三方服务共享信息,而无需公开用户的用户名/密码。本质上,OAuth是为第三方服务提供令牌的中间人,该令牌只允许共享特定的帐户信息。
换句话说,OAuth是一个过程,在该过程中,用户授权网站或应用程序访问另一个网站上的信息,而无需提供登录凭证。然后,OAuth确保请求信息的网站具有访问用户数据的权限。
OAuth 2.0是2012年对原始开放授权协议的重写,为现代web和非web客户端提供了更全面的解决方案。OAuth 2.0是当前授权软件的行业标准框架。
OAuth 2.0是一种授权协议,而不是身份验证协议。因此,它主要被设计为授予对一组资源(例如远程API或用户数据)的访问权的一种手段。
OAuth 2.0使用Access Tokens
。Access Token
是代表最终用户访问资源的授权的一段数据。OAuth 2.0没有定义访问令牌的特定格式。在某些上下文中,通常使用JSON Web令牌(JWT)格式。这使得令牌发行者能够在令牌本身中包含数据。出于安全原因,访问令牌可能包含到期日期。
角色的概念是OAuth2.0授权框架的核心规范的一部分。这些定义了OAuth 2.0系统的基本组件,如下所示:
Protocol Flow
+--------+ +---------------+
| |--(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
Figure 1 所示的抽象OAuth 2.0流程描述了四个角色之间的交互包括以下步骤:
(A)客户端向资源所有者申请授权。
(B)客户端接收资源所有者授权凭证。
(C)客户端携带授权凭证,向授权服务器申请令牌。
(D)授权服务器对客户端进行认证,确认无误,同意发放令牌。
(E)客户端携带令牌,向资源服务器申请资源。
(F)资源服务器验证令牌无误,同意向客户端开放资源。
权限授予( Authorization Grant)是资源拥有者同意授权请求(访问受保护资源)的凭据,客户端可以用它来获取access token
。 本规范定义了四种授权(grant)类型
authorization code
)implicit
)resource owner password credentials
)client credentials
)令牌过期,刷新令牌
+--------+ +---------------+
| |--(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
Figure 2所示的流程包括以下步骤:
(A)客户端携带授权凭证,向认证服务器申请令牌。
(B)认证服务器对客户端进行认证,确认无误,同意发放令牌。(访问令牌和刷新令牌)。
(C)客户端携带令牌,向资源服务器申请资源。
(D)资源服务器验证令牌无误,同意向客户端开放资源。
(E)重复步骤(C)和(D)直到访问令牌过期(无效)。如果客户端已知访问令牌过期,则跳到步骤(G); 否则,客户端会生成另一个受保护的资源请求
(F)由于访问令牌过期无效,资源服务器返回错误(无效的令牌)。
(G)客户端请求授权服务器刷新令牌。客户端身份验证的要求是基于客户端类型和授权服务器策略。
(H)授权服务器验证客户端及刷新令牌,确认有效,同意发放新的令牌(访问令牌和新的刷新令牌)。
response_type
:code
表示要求返回授权码,token
表示直接返回令牌client_id
:客户端身份标识client_secret
:客户端密钥redirect_uri
:重定向地址scope
:表示授权的范围,read只读权限,all读写权限grant_type
:表示授权的方式,authorization_code
(授权码)、password
(密码)、client_credentials
(凭证式)、refresh_token
更新令牌state
:应用程序传递的一个随机数,用来防止CSRF攻击。授权码是通过授权服务器来获得的,授权服务器是客户端和资源拥有者之间的媒介。与客户端直接向资源拥有者申请权限不同,客户端通过将资源拥有者引向授权服务器(通过[RFC2616]中定义的user-agent),然后授权服务器反过来将资源拥有者redirect到client(附带上authorization code)。
在将资源拥有者redirect到client(附带authorization code)之前,授权服务器验证资源拥有者并获取授权。因为资源拥有者仅与授权服务器进行身份验证,所以资源拥有者的凭据(用户名、密码等)永远不会泄露给客户端(尤其是第三方客户端)。
授权码有一些重要的安全优势,比如验证client的能力,比如直接将access token
传送给Client
而不是通过资源拥有者的user-agent(可能会将token泄露给第三方)。
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI ---->| |
| User- | | Authorization |
| Agent -+----(B)-- User authenticates --->| Server |
| | | |
| -+----(C)-- Authorization Code ---<| |
+-|----|---+ +---------------+
| | ^ v
(A) (C) | |
| | | |
^ v | |
+---------+ | |
| |>---(D)-- Authorization Code ---------' |
| Client | & Redirection URI |
| | |
| |<---(E)----- Access Token -------------------'
+---------+ (w/ Optional Refresh Token)
Note: The lines illustrating steps (A), (B), and (C) are broken into
two parts as they pass through the user-agent.
Figure 3: Authorization Code Flow
图3所示的流程包括以下步骤:
(A) 客户端将通过用户代理获取资源拥有者的授权。客户包括其客户端标识符、请求的范围、本地状态和重定向URL
(B) 授权服务器验证资源拥有者(通过用户代理)并确定资源拥有者是否授予或拒绝客户端的访问请求。
(C) 资源拥有者授予访问权限,则授权服务器使用前面提供的重定向URI(在请求中或客户注册时)。
(D) 客户端携带授权码、客户端凭证及重定向URI 向授权服务器申请身份验证
(E) 授权服务器验证客户端及授权码, 授权服务器验证客户端及刷新令牌,确认有效,同意发放访问令牌和刷新令牌(可选)。
https://${授权服务器}/oauth/authorize
?response_type=code
&client_id=${CLIENT_ID}
&redirect_uri=http://${授权服务资源}
&scope=read
http://${授权服务资源}?code=${AUTHORIZATION_CODE}
https://${授权服务器}/oauth/token
?client_id=${CLIENT_ID}
&client_secret=${CLIENT_SECRET}
&grant_type=authorization_code
&code=${AUTHORIZATION_CODE}
&redirect_uri=http://${授权服务资源}
{
"access_token":${ACCESS_TOKEN},
"token_type":"bearer",
"expires_in":172800,
"refresh_token":${REFRESH_TOKEN},
"scope":"read",
......
}
https://${授权服务器}/oauth/token
?grant_type=refresh_token
&client_id=${CLIENT_ID}
&client_secret=${CLIENT_SECRET}
&refresh_token=${REFRESH_TOKEN}
隐示模式是为在浏览器中使用诸如JavaScript之类的脚本语言而优化的一种隐示的授权码流程。在隐示模式中,直接将access token
而不是authorization code颁发给Client(通过资源拥有者的授权)。grant类型为implicit,所以没有中间环节(比如用来在稍后获取access token
的authorization code
)
在隐示模式中颁发access token
时,授权服务器没有对Client进行验证。在某些情况下,可以通过获取access token
的重定向URI来验证client。access token
可以通过访问资源拥有者的user-agent
暴露给资源拥有者或者其他的应用。
由于隐示模式减少了获取access token
的往返次数,所以可以提高某些客户端的响应能力和效率(比如一个运行在浏览器中的应用)。但需权衡使用隐示模式所带来的便捷性与其带来的安全隐患之间的利害关系,尤其相对授权码模式可用时。
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI --->| |
| User- | | Authorization |
| Agent -|----(B)-- User authenticates -->| Server |
| | | |
| |<---(C)--- Redirection URI ----<| |
| | with Access Token +---------------+
| | in Fragment
| | +---------------+
| |----(D)--- Redirection URI ---->| Web-Hosted |
| | without Fragment | Client |
| | | Resource |
| (F) |<---(E)------- Script ---------<| |
| | +---------------+
+-|--------+
| |
(A) (G) Access Token
| |
^ v
+---------+
| |
| Client |
| |
+---------+
Note: The lines illustrating steps (A) and (B) are broken into two
parts as they pass through the user-agent.
Figure 4: Implicit Grant Flow
图4所示的流程包括以下步骤:
(A) 客户端将通过用户代理获取资源拥有者的授权。客户包括其客户端标识符、请求的范围、本地状态和重定向URL
(B) 授权服务器验证资源拥有者(通过用户代理)并确定资源拥有者是否授予或拒绝客户端的访问请求。
(C) 假设资源拥有者授予访问权限,则授权服务器使用前面提供的重定向URI。重定向URI包括URI片段中的访问令牌。
(D) 用户代理将请求web托管的客户端资源。
(E) web托管的客户端资源返回一个网页(通常是带有嵌入式脚本的HTML文档)。
(F) 用户代理执行由web宿主提供的脚本本地客户端资源,提取访问令牌。
(G) 用户代理将访问令牌传递给客户端。
https://${授权服务器}/oauth/authorize
?response_type=token
&client_id=${CLIENT_ID}
&redirect_uri=http://${授权服务资源}
&scope=read
资源拥有者密码凭证(如用户名和密码)可以用来直接用来当做一种获取access token
的权限授予方式。凭证仅应当在资源拥有者高度信任client时使用(比如,应用是设备操作系统的一部分,或有较高权限的应用),并且其他授权模式(比如授权码模式)不可用时。
此授权类型需要client直接接触资源拥有者的凭证,资源拥有者的凭证仅被用于单次的获取access token
的请求。通过使用用户凭证来获取较长有效期的access token
或者refresh token
,此模式可消除client在将来需要授权时需获取资源拥有者凭证。
+----------+
| Resource |
| Owner |
| |
+----------+
v
| Resource Owner
(A) Password Credentials
|
v
+---------+ +---------------+
| |>--(B)---- Resource Owner ------->| |
| | Password Credentials | Authorization |
| Client | | Server |
| |<--(C)---- Access Token ---------<| |
| | (w/ Optional Refresh Token) | |
+---------+ +---------------+
Figure 5: Resource Owner Password Credentials Flow
图5所示的流程包括以下步骤:
(A) 资源拥有者向客户端提供其用户名及密码;
(B) 客户端携带资源拥有者敏感信息请求授权服务器;
(C) 授权服务器对客户端及资源拥有者进行认证,确认无误,同意发放令牌。
https://${授权服务器}/oauth/token
?grant_type=password
&username=${USERNAME}
&password=${PASSWORD}
&client_id=${CLIENT_ID}
当授权范围限于客户端控制下的受保护资源或先前与授权服务器一起拥有的受保护资源时,Client凭据(或其他形式的客户端身份验证)可用作权限授予。客户端凭证通常是客户端代表自己(客户端也是资源所有者)或基于先前与授权服务器一起授权请求访问受保护资源时用作权限授予。
+---------+ +---------------+
| | | |
| |>--(A)- Client Authentication --->| Authorization |
| Client | | Server |
| |<--(B)---- Access Token ---------<| |
| | | |
+---------+ +---------------+
Figure 6: Client Credentials Flow
图6所示的流程包括以下步骤:
(A) 客户端携带自身凭据请求获取令牌;
(B) 授权服务器对客户端进行认证,确认无误,同意发放令牌。
https://${授权服务器}/oauth/token
?grant_type=client_credentials
&client_id=${CLIENT_ID}
&client_secret=${CLIENT_SECRET}
您可能使用过OAuth,但甚至没有意识到。例如,当您授予网站访问您的Facebook信息的权限时,您使用的是开放授权。此协议非常有用,因为它允许您与第三方站点共享有限数量的信息,而不是通过您的登录凭证让他们完全控制您的帐户。
关于OAuth的一个常见误解是,该过程还验证用户的身份,即身份验证。因此,OAuth经常与单点登录(SSO)身份验证混淆。虽然这两个过程非常相似,甚至有一些基本特征,但它们有一个关键区别:SSO认证用户,而OAuth授权用户。
为了更好地理解差异,我们首先分析身份验证和授权的含义:
身份验证(Authentication) 是验证用户身份的行为。当用户输入用户名和密码(或使用无密码凭证)时,网站使用该信息通过将其与用户凭证的安全数据库进行比较来确认此人是预期用户。
授权(Authorization) 发生在用户经过身份验证之后。这是系统检查用户拥有哪些权限的时候。用户的权限决定了用户在网站上看到的内容,以及一旦您确认他们是他们所说的人,他们可以在网站上采取什么行动。
比较和对比这两个术语的最简单方法如下:
因此,没有认证就没有授权。然而,仅凭身份验证不足以保护帐户和提供特定权限,因此这两个过程是协同工作的。
OAuth的目的是确保第三方网站在使用身份验证方法验证用户身份后拥有访问用户信息的权限。