文章目录
1. 前言
建议大家先看看 阮一峰老师写的一系列文章,写的很好,比较容易理解:
阮一峰的网络日志 OAuth 2.0 的一个简单解释
阮一峰的网络日志 OAuth 2.0 的四种方式
阮一峰的网络日志 GitHub OAuth 第三方登录示例教程
阮一峰的网络日志 理解OAuth 2.0
2. 什么是OAuth 2.0?
OAuth 2.0是用于授权的行业标准协议。OAuth 2.0致力于简化客户端开发人员,Web应用程序,桌面应用程序,移动电话和客厅设备所提供特定的授权流程。
下文引用自 阮一峰的网络日志 OAuth 2.0 的四种方式
OAuth 2.0 的标准是 RFC 6749 文件。该文件先解释了 OAuth 是什么。
OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者。......资源所有者同意以后,资源服务器可以向客户端颁发令牌。客户端通过令牌,去请求数据。
2.1 说明一下出现的角色
在OAuth的定义中一共有4个角色:
资源所有者(resource owner)
。简单理解就是用户
。资源服务器(resource server)
。托管受保护资源的服务器,能响应访问资源的请求。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。客户端(client)
。简单理解就是第三方应用程序
,它需要访问用户
的数据。认证服务器(authorization server)
。当获取到用户
的授权,并且认证通过后,会向第三方应用程序
颁发令牌(token)。
在传统的客户端-服务器
身份验证模型中, 第三方应用程序
通过使用资源所有者
的凭证与认证服务器
进行身份验证向资源服务器
请求访问受保护的资源。为了让 第三方应用程序
能访问受限资源,资源所有者
需要将凭证共享给 第三方应用程序
,这就造成了一下几个问题和限制:
- 为了在未来也能访问这些资源,
第三方应用程序
需要存储资源所有者的凭证(通常是用户名+密码); - 即是密码存在安全漏洞,
认证服务器
仍然需要验证密码; - 无法限制
第三方应用程序
的访问权限范围和访问有效期; 资源所有者
不能在不影响其他第三方应用程序
的前提下,撤销某一个第三方应用程序
的访问权限,而且只能通过修改密码才能撤销其访问权限;- 这些
第三方应用程序
中的因任何一个被破解,则资源所有者
的密码和数据都会暴露。
3. 协议流程
+--------+ +---------------+
| |--(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 ---| |
+--------+ +---------------+
图1:抽象的协议流程
(A) 第三方应用程序
向资源所有者
请求授权。第三方应用程序
可以直接向资源所有者
提出授权请求(如图所示),或者最好是通过认证服务器
作为中介间接进行授权。
(B) 资源所有者
同意授权,返回给第三方应用程序
一个授权许可(使用的授权方式不同,授权许可也就不同,如使用授权码方式,则授权许可即授权码)。
© 第三方应用程序
携带着之前的授权许可数据向认证服务器
请求访问令牌(access token
) 。
(D) 认证服务器
对第三方应用程序
进行身份验证,如果有效,颁发访问令牌。
(E) 第三方应用程序
携带着访问令牌,向资源服务器
请求所要的资源。
(F) 资源服务器
验证访问令牌是否有效,如果有效,则返回对应的资源。
4. 四种授权方式
4.1 授权码授权(Authorization Code Grant)
简单说就是:
-
用户访问第三方应用程序;
-
第三方应用程序
将用户定向到认证服务器
; -
认证服务器
对用户进行认证(让用户登录),并询问用户是否同意授权,用户同意,且在用户认证通过后,认证服务器
将用户重定向回第三方应用程序
(携带着授权码等信息); -
第三方应用程序
携带着授权码向认证服务器请求access token
; -
认证服务器
验证通过后,将access token
和refresh token
等返回给第三方应用程序
; -
至此,
第三方应用程序
可使用该access 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) 图 2:授权码流程
(A)第三方应用程序
将资源所有者
的User-Agent(就理解成手机应用、浏览器等)
定向到认证服务器
。 此过程中,第三方应用程序
需要提供一下信息:client id
(客户端id),request scope
(请求的范围),local state
(本地状态)和 redirection URI
(重定向URI),一旦授予(或拒绝)访问权限,认证服务器便
会将User-agent重定向回这个URI
。
(B)认证服务器
验证资源所有者
的身份,并询问是否同意授权;
(C)如果资源所有者
同意第三方应用程序
的访问请求授权,认证服务器
会重定向回第三方应用程序
(携带着授权码和其他数据);
(D)第三方应用程序
携带着授权码向认证服务器
请求访问令牌(access token
);
(E)认证服务器
验证第三方应用程序
的身份,验证授权码的有效性,并确保在步骤(C)中接收到的重定向URI
与用于重定向到第三方应用程序
的URI
匹配。如果都有效,认证服务器会
返回access token
和refresh token
给第三方应用程序。
4.2 隐式授权(Implicit Grant)
这种方式只能用于获取access token
,不支持获取refresh token
。使用此方式的第三方应用通常是在浏览器中使用脚本语言(如JavaScript)实现的。
在授权码方式中,认证请求(获取授权码的请求)和获取access token
的请求是两个请求,而在隐式授权中在认证请求的响应中就包含了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 |
| |
+---------+
图 3: 隐藏式流程
(A)第三方应用程序
将资源所有者
的User-Agent(如,浏览器,手机应用)
定向到认证服务器
。需要包含:client id
,requested scope
,local state
,redirection URI
,一旦授予(或拒绝)访问权限,认证服务器便
会将User-agent
重定向回这个URI
。
(B)认证服务器
验证资源所有者
的身份,并询问是否同意授权;
(C)如果资源所有者
同意第三方应用程序
的访问请求授权,认证服务器
会重定向回第三方应用程序
(以URI fragment
的方式携带着access token);
(D)资源所有者
的User-Agent
向资源服务器
发送请求(不携带上一步返回的access token
,此token由User-Agent
保管)。
(E)资源服务器
返回一个web页面,该页面中的脚本能够获取access token
和其他在URI fragment
中的数据。
(F)User-Agent
执行(E)中返回的脚本,获得access token
。
(G)User-Agent
将此access token
发送给第三方应用程序
。
4.3 用户密码凭证授权(Resource Owner Password Credentials Grant)
此方式适用于资源所有者充分相信第三方应用程序的场景。认证服务器在用这种授权方式时应格外小心,仅在其他方式不可行时才使用它。
在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式
+----------+
| Resource |
| Owner |
| |
+----------+
v
| Resource Owner
(A) Password Credentials
|
v
+---------+ +---------------+
| |>--(B)---- Resource Owner ------->| |
| | Password Credentials | Authorization |
| Client | | Server |
| |<--(C)---- Access Token ---------<| |
| | (w/ Optional Refresh Token) | |
+---------+ +---------------+
图 4:密码式流程图
(A)资源所有者将用户名和密码提供给第三方应用程序;
(B)第三方应用程序(携带着用户名和密码)向认证服务器请求access token
;
(C)认证服务器对第三方应用程序的身份和其提供的用户名和密码进行验证,如果有效,则颁发access token
。
4.4 客户端凭证授权(Client Credentials Grant)
客户端凭证模式(Client Credentials Grant
)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。
+---------+ +---------------+
| | | |
| |>--(A)- Client Authentication --->| Authorization |
| Client | | Server |
| |<--(B)---- Access Token ---------<| |
| | | |
+---------+ +---------------+
图 5:Client Credentials流程图
(A)第三方应用程序请求认证服务器进行身份验证和access token
;
(B)认证服务器认证通过后,为第三方应用程序颁发一个access token
。
5. 其他操作
5.1 使用access token
每个发到API
的请求都必须带有令牌,在请求头中,加上一个Authorization
字段,其值为令牌的值。
5.2 更新access token
在授权码模式和密码模式中,认证服务器除了返回access token
之外,还会返回refresh token
。这个refresh token
就是用来更新access token
。refresh token
的生命期长于access token
。需要注意的是,资源服务器用不到refresh token
,认证服务器才会用refresh token
。
如果用户访问的时候,客户端的"访问令牌"已经过期,就可以使用"更新令牌"去请求认证服务器获得一个新的访问令牌。官网中的例子如下:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
新令牌的scope
必须小于等于原来的scope
(access token
和refresh token
都是这样)。
更新过期的access 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 +---------------+
图 6:Refreshing an Expired Access Token
(A)第三方应用程序
向认证服务器
请求进行身份验证,和访问令牌(access token)
;
(B)认证服务器
验证第三方应用程序
的身份,并验证授权,若有效,则颁发一个access token
和一个refresh token
;
(C)第三方应用程序
携带着access token
去请求资源服务器
获取某些资源;
(D)资源服务器
验证access token
,如果有效,则处理该请求;
(E)重复(C)和(D)操作,知道access token
过期。如果第三方应用程序
知道access token
过期了,直接进行(G);否则,第三方应用程序
继续向资源服务器
发起访问资源的请求;
(F)由于access token
已经失效,资源服务器
告诉第三方应用程序
它的access token
失效了;
(G)第三方应用程序
携带着refresh token
去请求认证服务器
,让其验证第三方的身份,并要求返回新的access token
;
(H)认证服务器
验证第三方应用程序
的身份和refresh token
是否有效,若有效,则颁发一个新的access token
(也可以颁发一个新的refresh token
)给第三方应用程序
。
6. 总结
在OAuth 2.0
中token
有两种:access token
和refresh token
。前者用于获取资源,后者用于获取新的access token
。OAuth 2.0
实质是一种授权机制,让A应用在经过用户同意后可以访问该用户在B应用中的某些数据。
7. 参考文献
[1] OAuth 2.0 官网
[2] RFC 6749
[3] OAuth2.0的四种授权模式
[4] 阮一峰的网络日志 OAuth 2.0 的一个简单解释
[5] 阮一峰的网络日志 OAuth 2.0 的四种方式
[6] 阮一峰的网络日志 GitHub OAuth 第三方登录示例教程