概述
OAuth 2.0 授权框架能够是第三方应用获取应用被保护的服务资源,它是一种授权互联网标准,由IETF(Internet Engineering Task Force)管理发布。
本文主要参考材料为 RFC 6749
初步理解
接下来以一个生活中的例子来简单解释OAuth2的应用场景。
我家所在的小区门禁系统升级,用户可以下载物业的手机APP,注册用户并通过物业审核之后,就可以使用APP中的“蓝牙开门”功能开启大门。
有一次,朋友给我打电话说要到我家拜访,通过访客邀请功能填写基本的信息,然后发送一个微信小程序链接给朋友
朋友点开小程序,点击一键开门就可以进入小区,当天有效并且限制使用8次
整个过程就相当于一次授权:
小区可以理解成被保护的资源,我本人拥有APP的用户和密码,登陆后可以使用一键开门进入小区。
朋友打电话给我申请授权,我通过APP发放一个凭证(微信小程序),朋友可以在凭证有效期内进入小区。
授权机制可以方便的允许第三方(朋友)访问被保护的资源(小区),同时不需要提供用户密码。
OAuth2.0标准
OAuth2.0中的角色
- resource owner: 资源拥有者,可以对资源进行访问授权,通常是指应用的终端用户
- resource server:资源服务器,包含被保护的资源,可以接受携带访问凭证的请求
- client:客户端,即第三方应用,会代表resource owner请求访问resource server的资源
- authorization server:认证服务器,为客户端颁发访问凭证
- user-agent:用户代理,通常就是指Web浏览器
OAuth2.0的流程
(A) 客户端(Client)向资源拥有者(Resource Owner)申请授权,资源拥有者(Resource Owner)可以直接授权,但最好是通过Autherization进行授权
(B)客户端(Client)获得授权的允许凭据(Authorization Grant),在OAuth2.0中该凭据的获取有四种类型,授权码、隐藏式、用户密码和客户端凭证
(C)客户端(Client)使用授权凭据向授权服务器(Authorization Server)申请访问凭证(Access Token)
(D)认证服务器(Authorization Server)验证申请凭据(Authorization Grant),验证通过后颁发访问凭证(Access Token)
(E)客户端(Client)使用访问凭证(Access Token)访问资源服务器(Resource Server)
(F)资源服务器(Resource Server)验证访问凭证(Access Token),验证通过后对客户端(Client)请求进行处理并返回结果
刷新凭证(Refresh Token)
刷新凭证(Refresh Token)是由认证服务器(Authorization Server)颁发给客户端(Client),用于在当前凭证失效或者过期时,重新获取一个新的访问凭证(Access Token)。但颁发刷新凭证(Refresh Token)对于认证服务器(Authorization Server)是可选择的功能,如果支持,刷新凭证(Refresh Token)会与访问凭证(Access Token)一同颁发
(A)客户端(Client)使用授权凭据(Authorization Grant)请求访问凭证(Access Tonken)
(B)认证服务器(Authorization Server)验证凭据通过后,颁发访问凭证(Access Token)和刷新凭证(Refresh Token)
(C)客户端(Client)使用访问凭证(Access Token)访问资源服务器(Resource Server)
(D)资源服务器(Resource Server)验证访问凭证(Access Token),验证通过对请求进行处理
(E)步骤©、(D)会不断重复,直到访问凭证(Access Token)过期,此时流程会跳转至(G)
(F)由于凭证过期,资源服务器会返回凭证过期的错误
(G)客户端(Client)使用刷新凭证(Refresh Token)请求新的访问凭证(Access Token)
(H)认证服务器验证刷新凭证,验证通过,办法新的访问凭证和刷新凭证
客户端的授权类型
授权码模式
流程
(A)客户端(Client)使浏览器(User-Agent)跳转至认证服务器(Authorization Server)的认证接口,请求信息包含客户端标识、请求范围、跳转URI(跳转至客户端,用来提取授权码)
(B)认证服务器(Authorization Server)验证资源所有者(Resource Owner),通常就是用户填写用户名密码并确认是否授权
(C)认证服务器(Authorization Server)如果验证通过,则会返回给浏览器(User-Agent)步骤(A)中发送的跳转URI,跳转至客户端(Client),跳转URI中同时会携带授权码(Authorization Code)
(D)客户端(Client)使用授权码(Authorization Server)向认证服务器(Authorization Server)请求访问凭证(Access Token),同时还会携带跳转URI用于客户端提取访问凭证(Access Token)
(E)认证服务器(Authorization Server)验证授权码(Authorization Server),验证通过后颁发访问凭证(Access Token)
授权码请求(Authorization Request)
请求包含以下参数:
- response_type:表示授权类型,必选项,此处的值固定为"code"
- client_id:表示客户端的ID,必选项
- redirect_uri:表示重定向URI,可选项
- scope:表示申请的权限范围,可选项
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
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
授权码响应(Authorization Response)
响应包含以下参数:
- code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
访问凭证请求(Access Token Request)
- grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
- code:表示上一步获得的授权码,必选项。
- redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
- client_id:表示客户端ID,必选项。
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
访问凭证响应(Access Token Response)
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
- expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
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)通过浏览器(User-Agent)跳转至认证服务器(Authorization),请求中包含客户端标识和跳转URI
(B)用户(Resource Owner)填写用户密码,认证服务器(Authorization)对其进行认证
(C)认证服务器(Authorization)认证通过后,返回之前传入的跳转URI至浏览器,跳转URI中以锚点(#)的方式包含访问凭证(Access Token)
(D)浏览器(User-Agent)跳转至URI指向的客户端的Web服务器,浏览器(User-Agent)保留锚点之后的信息
(E)客户端Web服务器返回一个web页面(其中包含嵌入的脚本),web页面能够提取锚点中的信息,并发送完整的URI至客户端
(F)浏览器(User-Agent)执行Web页面中的脚本
(G)浏览器(User-Agent)发送访问凭证(Access Token)至客户端(Client)
Authorization Request
参数包括:
- response_type:表示授权类型,此处的值固定为"token",必选项。
- client_id:表示客户端的ID,必选项。
- redirect_uri:表示重定向的URI,可选项。
- scope:表示权限范围,可选项。
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
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
Access Token Response
参数包括:
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,该值大小写不敏感,必选项。
- expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
&state=xyz&token_type=example&expires_in=3600
用户密码模式
流程
(A)资源所有者(Resource Owner)提供给客户端(Client)用户名和密码
(B)客户端(Client)使用用户名/密码,向认证服务器(Authorization Server)请求访问凭证(Access Token)
(C)证服务器(Authorization Server)验证用户名/密码,验证通过后颁发访问凭证(Access Token)
访问凭证请求 Access Token Request
参数包括:
- grant_type:表示授权类型,此处的值固定为"password",必选项。
- username:表示用户名,必选项。
- password:表示用户的密码,必选项。
- scope:表示权限范围,可选项。
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
访问凭证响应 Access Token Response
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)向认证服务器(Authorization Server)请求访问凭证(Access Token)
(B)认证服务器(Authorization Server)验证客户端(Client),如果验证通过则颁发访问凭证(Access Token)
Access Token Request
参数:
- grant_type:表示授权类型,此处的值固定为"client_credentials",必选项。
- scope:表示权限范围,可选项。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
Access Token Response
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"
}