OAuth2.0
OAuth 即 Open Authorization,是“开放授权”的简写,它是一个关于授权(authorization)的开放网络标准。一句话,OAuth2.0 是一种授权协议。
无论使用哪种三方平台,最重要的一步就是获取三方授权的 token,当然不同的厂商叫法不一样,有的叫 access_token,有的叫 oauth_token,还有的叫 code。关键是拿到这个凭证后,你就有权限继续去三方获取用户的昵称、头像、动态、好友列表之类的信息。当然,权限也是有范围和有效期的。
在整个过程中,用户凭据未向第三方应用暴露,用户授权的是访问令牌(Access Token),它通常有时间限制,并且只允许访问特定范围的资源。OAuth 2.0提供了一种既安全又方便的方式来实现免登,因为用户只需要与他们信任的认证服务器进行凭据交互。
此外,刷新令牌(Refresh Token)可能被认证服务器颁发,用以在访问令牌失效时获取新的访问令牌,而不需要用户重新进行授权,进一步提升了用户体验。
授权流程
授权方式
一、授权码模式(最安全)
Authorization Code
指的是第三方应用先申请一个授权码,然后再用该码获取令牌。
最常用,安全性最高的流程。适用于有后端的web应用。由前端传送授权码,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后分离,可以避免令牌client_secret泄露。
(A) 用户访问客户端,客户端将用户重定向到认证服务器(例如QQ等),携带以下参数client_id、redirect_uri等;例如a网站向b网站:https://b.com/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read
(B) 用户选择是否授权;
(C) 如果用户同意授权,认证服务器重定向到客户端事先指定的地址,而且带上授权码(code);如果授权失败,会携带错误码重定向到指定地址。例如b网站回调a网站地址:https://a.com/callback?code=AUTHORIZATION_CODE
(D) 客户端收到授权码,带着前面的重定向地址,向认证服务器申请访问令牌token;前端通过携带code请求后端,由后端代理请求认证服务器获取token。后端携带client_secret请求认证服务器例如:https://b.com/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL
(E) 认证服务器核对授权码与重定向地址,确认后向客户端发送访问令牌和更新令牌(可选),access_token和refresh_token。
/oauth/authorize 前端调用打开登陆地址,例如跳转qq登陆页获取授权
| 参数名称 | 参数含义 | 是否必须 |
|---|---|---|
| response_type | 授权类型,一般为code,其他例如token | 必须 |
| client_id | 客户端ID,客户端到资源服务器注册的ID,例如在开放平台注册的appId | 必须 |
| redirect_uri | 重定向URI,授权成功后要重定向到的地址 | 可选 |
| scope | 申请的权限范围,多个逗号隔开,例如头像、昵称等 | 可选 |
| state | 客户端的当前状态,可以指定任意值,认证服务器会原封不动的返回这个值 | 推荐 |
/oauth/token 后端调用
| client_id | 表明身份-客户端id |
|---|---|
| client_secret | 表明身份-保密参数,因此只能在后端发送请求 |
| grant_type | 授权方式,默认为AUTHORIZATION_CODE |
| code | 授权码 |
| redirect_uri | 令牌颁布后的回调网址 |
1 | |
二、简化(隐式)模式(纯前端)
对于纯前端应用,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)”隐藏式”(implicit)。
A网站提供一个链接,要求用户跳转B网站授权用户数据给A网站
1 | |
response_type参数为token,表示要求直接返回令牌
用户在B网站登录并且同意授权给A网站,B网站就会跳回redirect_ui并且令牌会通过url传递
1 | |
注意: 令牌的位置是URL锚点(#携带参数),不是查询字符串。是因为OAuth2.0允许跳转网址是HTTP协议,存在“中间人攻击”风险,而浏览器跳转时,锚点不会发送到浏览器,减少了令牌泄露的风险。
缺点:
- 令牌是直接传递给前端的,有一定的安全风险,只能用于一些安全性不高的场景。
- 令牌的有效期非常短,通常是会话内有效
三、密码式(高度信任应用)
如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为”密码式”(password)。
A网站要求用户提供B网站的用户名和密码。拿到以后,A直接向B请求令牌
1 | |
B验证用户身份无误后,直接给出令牌(无需跳转),令牌会作为HTTP回应在JSON数据里被拿到
1 | |
需要给出用户名和密码,风险很大,只适用于其他授权方式无法采用的情况,并且是用户高度信任的应用。
四、凭证式(命令行应用)
客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向”服务提供商”进行授权。
适用于没有前端的命令行应用,即在命令行下请求令牌。一般用来提供给我们完全信任的服务器端服务。
A应用在命令行向B发出请求
1 | |
B网站通过验证之后,直接返回令牌
{
“access_token”:”ACCESS_TOKEN”, # 令牌
“token_type”:”bearer”,
“refresh_token”:”REFRESH_TOKEN”, # 用于刷新
“scope”:”read”
}
这种方式给出的令牌,是针对第三方应用的,不是针对客户的,所以有可能多个用户共享一个令牌。
令牌的使用
A网站拿到令牌之后,就可以向B网站的API请求数据了。
每个发到API的请求,都必须带有令牌。具体做法是在请求头信息上,带上Authorization字段,令牌就存放在这个字段里面。
1 | |
令牌的更新
如果令牌的有效期到了,重走上面的流程体验性不好,所以OAuth2.0允许用户自动更新令牌。
更新方法
B网站颁布令牌的时候,一次性颁布两个令牌:
- 一个用于获取数据
- 一个用于获取新的令牌(refresh token字段)
令牌到期前,用户通过refresh token发送一个请求,去更新令牌。
1 | |
response
1 | |
