OAuth 2.0 rfc6749 规范-带目录,阅读 RFC 文档的 工具
OAuth 是授权(authorization)框架,描述了系统中不同角色(服务提供商、用户、第三方应用)之间怎么实现交互。目前广泛使用的是 2.0 版本。
常见的应用场景(估计所有人都见过):授权登录注册。比如微信有很多用户,且微信提供了 OAuth2 接口。在我的网站上,为了简化用户注册流程,对接了微信提供的这个接口,并且在注册页面提供一个“通过微信登录”的链接或二维码,用户点击后会跳转到微信的授权登录页面(或者微信扫码进入授权页面),微信在用户授权后会将这个用户的基本信息发到我的网站,完成注册。注册后,每次都可以通过微信授权登录了。
如果需要做微信这样的平台型应用,为很多合作伙伴提供授权认证服务,可以考虑搭建自己的 OAuth 2.0 系统。但是要明白,这是挺复杂的一个系统。对于大部分应用开发人员,需要掌握的是如何调用其他平台的接口。
OAuth2 提供了 4 种角色:
另外的常用名词有:
token 都是字符串,授权服务器需要保存所有的 token 及对应的授权信息,以便校验请求。
用于访问受保护资源的凭证。这个凭证表示特定访问范围和可用时间,由资源所有者授权,并由资源服务器和授权服务器执行,并发给客户端。
对资源的访问,需要 access token。
用于再次获取 access token 的凭证。这是可选项,可以自行决定是否让授权服务器发布 refresh token。如果发布 refresh token,会跟 access token 一同发出。refresh token 可以在 access token 失效后获取新的 access token,也可以获取更多一个 access token。
refresh token 只会跟授权服务器交互,不会发送到资源服务器。
Client 有两种类型:
公开的:密码会发给 Client,所以 Client 可能会泄露密码。这个过程中密码传输到终端设备,例如浏览器,APP。
私有的:密码不会发给 Client,所以 Client 不会泄露密码。
Web 应用:各个网站的微信授权登录就是典型的 Web 应用
User Agent(用户代理)应用:对于浏览器上运行的 JavaScript 应用,浏览器就是用户代理。用户代理应用可以保存在 web 服务器上,但应用程序只运行一次下载的用户代理。
原生应用:无法保证 secret 的安全。
详细差异可以参考 这里。
参考 RFC6750
通过在请求中简单地包含访问令牌字符串来使用:
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer mF_9.B5f-4.1JqM
通过发出消息认证代码(MAC)密钥以及用于签署 HTTP 请求的某些组件的访问令牌来使用:
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: MAC id="h480djs93hd8",
nonce="274312:dj83hs9s",
mac="kDZvddkndxvhGRXZhvuDjEWhGeE="
+--------+ +---------------+
| |--(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: 抽象的协议流程
详细步骤如下:
在步骤 B 中,客户端可以获得用户的授权。有四种授权模式。
第三方应用必须得到用户授权(authorization grant)后才能获得访问令牌(access token)。OAuth2 支持四种授权模式:
另外,对于已经授权的 Client,还有两种方式可以再次获取 access token:
最常用,微信、GitHub 等的授权登录注册就是这种方式。使用这种模式时,授权服务器会直接将授权发送到客户端的后台服务器,不需要经过用户代理,安全可靠。
+----------+
| 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)
注意:说明步骤(A),(B)和(C)的行在通过用户代理时分为两部分。
Figure 3: 授权码模式的流程
授权码模式用于获取访问令牌和刷新令牌,并针对机密客户端进行了优化。授权码模式基于重定向,授权开始时从客户端跳转到授权服务器的页面,授权完成后授权服务器后台通知客户端,同时跳转回客户端的页面。客户端必须能够与资源所有者的用户代理(通常是 Web 浏览器)进行交互,并且能够从授权服务器接收传入请求。
客户端通过 GET 方式使用以下参数来构造请求 URI:
授权请求示例:
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
授权服务器的响应也是“application/x-www-form-urlencoded”格式,包含以下参数:
授权响应示例:
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
客户端通过 POST 方式使用“application/x-www-form-urlencoded”格式将以下参数来构造请求 URI:
示例:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
授权成功后,响应包含以下参数:
示例:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
+----------+
| 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 |
| |
+---------+
注意:说明步骤(A)和(B)的行在通过用户代理时分为两部分。
Figure 4: 隐式授权模式的流程
客户端通过添加下面的参数来构造请求 URI
客户端使用 HTTP 重定向响应或通过用户代理可用的其他方式将资源所有者定向到构造的 URI。示例:
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
授权服务器必须验证 redirect_uri 参数是否和客户端预留的参数一致。
用户授权后,授权服务器会颁发一个 access token 并发送到客户端,可用参数如下:
注意:这里没有 refresh token。
示例:
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
&state=xyz&token_type=example&expires_in=3600
+----------+
| 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: 密码模式流程
资源所有者将用户名和密码发送给客户端,然后客户端用这些凭证获取授权。
客户端通过 GET 方式使用以下参数来构造请求 URI:
授权请求示例:
POST/token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
授权成功后,响应包含以下参数:
示例:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
+---------+ +---------------+
| | | |
| |>--(A)- Client Authentication --->| Authorization |
| Client | | Server |
| |<--(B)---- Access Token ---------<| |
| | | |
+---------+ +---------------+
Figure 6: Client Credentials Flow
客户端以自己的名义,而不是以用户的名义,向”服务提供商”进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求”服务提供商”提供服务,其实不存在授权问题。
客户端通过 GET 方式使用以下参数来构造请求 URI:
授权请求示例:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
授权成功后,响应包含以下参数:
示例:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}
+--------+ +---------------+
| |--(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: 刷新过期的 Access Token
客户端通过 GET 方式使用以下参数来构造请求 URI:
授权请求示例:
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
手机扫一扫
移动阅读更方便
你可能感兴趣的文章