OAuth 2.0
是一种授权框架,用于授权第三方应用访问用户的资源,比如用户的照片、个人信息等。OAuth 2.0
定义了四种授权方式:授权码模式、隐式授权模式、密码模式和客户端模式。
OAuth 2.0
具有高度的安全性和可扩展性,被广泛应用于各种开放平台的接口鉴权,是目前应用最广泛的开放平台鉴权方式之一,。
密码模式(Password Grant):用户将用户名和密码发送给第三方应用程序,第三方应用程序直接向授权服务器请求访问令牌。
客户端模式(Client Credentials Grant):适用于没有用户交互的应用程序,客户端使用其客户端凭证直接向授权服务器请求访问令牌。
用户在授权页面输入用户名和密码后,服务器返回授权码,然后第三方应用程序使用授权码请求访问令牌。
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统,微信OAuth2.0授权登录目前支持authorization_code模式。
用户访问客户端,后者将前者导向认证服务器。
用户选择是否给予客户端授权。
假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。
客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
下面是上面这些步骤所需要的参数。
A步骤中,客户端申请认证的URI,包含以下参数:
response_type:表示授权类型,必选项,此处的值固定为"code"
client_id:表示客户端的ID,必选项
redirect_uri:表示重定向URI,可选项
scope:表示申请的权限范围,可选项
state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
|
C步骤中,服务器回应客户端的URI,包含以下参数:
code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数
。
|
D步骤中,客户端向认证服务器申请令牌的HTTP请求,包含以下参数:
grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
code:表示上一步获得的授权码,必选项。
redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
client_id:表示客户端ID,必选项。
|
E步骤中,认证服务器发送的HTTP回复,包含以下参数:
access_token:表示访问令牌,必选项。
token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
|
从上面代码可以看到,相关参数使用JSON格式发送(Content-Type: application/json)。此外,HTTP头信息中明确指定不缓存。
access_token是调用授权关系接口的调用凭证,由于access_token有效期(目前为2个小时)较短,当access_token超时后,可以使用refresh_token进行刷新,access_token刷新结果有两种:
若access_token已超时,那么进行refresh_token会获取一个新的access_token,新的超时时间;
若access_token未超时,那么进行refresh_token不会改变access_token,但超时时间会刷新,相当于续期access_token(注意,微信开放平台是在原来的access_token上做延时,有的开放平台是直接换一个新的access_token)。
refresh_token拥有较长的有效期(30天),当refresh_token失效后,需要用户重新授权。
因为access_token是需要频繁在网络上传输的,因此被窃取的风险大,所access_token的有效时间设置较短;refresh_token仅仅在续签access_token时会在网络上传输,被窃取的风险相对小点,因此refresh_token拥有较长的有效期。这样一长一短的双token机制会比较安全。
双Token机制更为安全,而且可以很好的处理在线、离线续签的问题
OAuth 2.0 简化模式(Implicit Flow)是 OAuth 2.0 的一种授权方式,主要用于移动应用或 Web 应用中的前端客户端(例如 JavaScript 应用)的授权。
简化模式的主要特点是在授权流程中省略了授权码的获取过程,从而简化了授权流程。相对于授权码模式,简化模式的实现更为简单,但安全性也相应较低,客户端在获取授权码时,直接将访问令牌返回给客户端。
|
前端客户端(如 JavaScript 应用)向认证服务器发起授权请求。
认证服务器要求用户进行身份验证(如果用户没有登录)。
用户进行身份验证后,认证服务器返回授权码。
前端客户端从 URL 中解析授权码。
前端客户端使用授权码向认证服务器请求访问令牌。
认证服务器返回访问令牌。
前端客户端使用访问令牌向资源服务器请求受保护的资源。
对于简化模式而言,客户端只需要初始化一次请求,我们称这样的请求为授权请求(Authorization Request)。下面是一个授权请求的示例:
|
授权请求的参数含义如下:
response_type:必须参数。在简化模式下response_type的值必须为token,表明客户端在这种模式下期望授权服务器向它直接响应一个访问令牌(Access Token)。
client_id:必须参数。客户端的唯一标识,这是客户端注册的主要产物。
state:推荐参数。客户端负责该参数的初始化,授权服务器会原封不动地将该参数的值返回给客户端。该参数可以有效防范可能发生的跨站请求伪造攻击(CSRF)。我们在OAuth 2.0的安全篇还会向你详细介绍该参数的详细使用说明。
redirect_uri:该参数表示用户在授权完成后授权服务器向客户端返回响应的端点,无论是返回访问令牌(Access Token)的成功响应,还是返回错误消息的异常响应。该参数值必须与OAuth 2.0客户端注册时提供的授权回调URI完全匹配。如果该值与提供的client_id对应的授权重定向URI不匹配,则会得到一个redirect_uri_mismatch的错误。
scope:可选参数,表示客户端请求授权的访问权限范围,我们在第(5)小节详细讨论了该参数。一般是以空格分隔、区分大小写的字符串列表,例如“read write”。该参数具体需要参阅授权服务方提供的用户文档。
当授权服务器的授权端点收到上面客户端初始化的授权请求后,最主要的它将验证client_id和redirect_uri参数的合法性,如果这些参数有效,它将向客户端返回成功的响应。下面是一个成功响应的示例:
|
值得注意的是,在简化模式下响应的所有重要信息都包含URI片段中(URI Fragment),RFC 3986规范定义了Fragment的详细语法。这是OAuth工作组尽量减少简化模式可能存在的安全风险的最大努力,如果浏览器对一个带有Fragment的地址发起Ajax请求,那么Fragment的部分不会被发送到服务器,因此只有颁发令牌的授权服务器和Web浏览器能获取到访问令牌的值,但是Fragment的部分仍然可以通过referer头和浏览器历史记录获取。
access_token:必须参数。这是最重要的参数,客户端最终代表终端用户访问终端用户资源的“钥匙”。
state:如果客户端初始化的授权请求中有该参数,那么授权服务器应该原封不动地将该参数值返回给客户端。
token_type:必须参数。授权服务器颁发的令牌的类型。一般该值是“bearer”。如果你对Bearer Token感兴趣,你可以阅读RFC 6750文档。
expires_in:可选参数。以秒为单位的访问令牌的生存期。该参数为非必需参数,如果缺省这个参数,授权服务器必需以其他方式告知客户端令牌的剩余生命周期。
scope:可选参数。表示客户端请求授权的访问权限范围。如果授权服务器颁发的访问令牌绑定的权限范围和授权请求中客户端申请的权限范围一致,则可以缺省该参数。否则授权服务器必须显示告知权限范围发生变化。
简化模式省略了授权码的获取过程,从而简化了授权流程。这里的令牌直接传递给客户端,而没有通过授权码的方式进行保护,因此安全性较低。
密码模式(Resource Owner Password Credentials Grant)适用于客户端与用户之间存在一定信任关系的场景。在密码模式中,客户端直接向授权服务器请求授权,使用用户的用户名和密码作为授权凭证,从而获取access_token,然后使用access_token访问受保护的资源。
密码模式虽然简单,但存在一些安全风险,例如,客户端可能会保存用户的密码,从而导致密码泄露。因此,在使用密码模式时,需要根据具体的业务需求和安全要求,对授权服务器和资源服务器进行适当的配置和实现。
用户向客户端提供用户名和密码。
客户端将用户名和密码发给认证服务器,向后者请求令牌。
认证服务器确认无误后,向客户端提供访问令牌。
B步骤中,客户端发出的HTTP请求,包含以下参数:
grant_type:表示授权类型,此处的值固定为"password",必选项。
username:表示用户名,必选项。
password:表示用户的密码,必选项。
scope:表示权限范围,可选项。
|
C步骤中,认证服务器向客户端发送访问令牌。
|
适用于没有用户交互的应用程序,客户端使用其客户端凭证直接向授权服务器请求访问令牌。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。
客户端向认证服务器进行身份认证,并要求一个访问令牌。
认证服务器确认无误后,向客户端提供访问令牌。
A步骤中,客户端发出的HTTP请求,包含以下参数:
granttype:表示授权类型,此处的值固定为"clientcredentials",必选项。
scope:表示权限范围,可选项。
|
认证服务器必须以某种方式,验证客户端身份。
B步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。
|