OAuth2.0理解
接触到使用了OAuth2.0的互联网开放平台(如微信、新浪微博等)开发已经时间不短,之前一直是根据文档去拿token实现需求的功能,没有完全明白这要来来回回拿code、accessToken、refreshToken有什么意义
应用场景
理解一个设计标准,必须要明白他要解决的问题,其中耿介才能明了
此处试图用一个很常见的生活场景来还原OAuth2.0要解决的问题:
我有个朋友叫做“团长”,他经常叫我帮他发送体检报告、打印简历之类的事。于是就需要我登录他的163邮箱,为了让我登录邮箱,传统的方式就是,他必须把邮箱的账号和密码告诉我。
这样的授权方式会面临几个比较大的问题:
- 我为了方便以后帮团长打简历,必须要保存团长的密码,这样很不安全。
- 团长其实是不希望我看见他跟老婆的私人邮件的,但是密码没有这样的权限控制,也没办法限制授权的有效期。
- 团长只有修改密码,才能收回对我的授权,而这样团长的其他助理也会全部失去授权。
- 一旦我在登录过程中,有人在我身后看到了我输入的密码,团长的密码就会泄露出去,团长的所有数据会全部泄露。
OAuth的作用就呼之欲出了。
名词定义
对应以上的场景,我们来做出以下定义:
- 客户端,第三方程序,即上文所说的我
- 服务提供商,即上文中的163邮箱
- 用户,资源所有者,即上文中的团长
OAuth思路
OAuth在”客户端”与”服务提供商”之间,设置了一个授权层(authorization layer)。”客户端”不能直接登录”服务提供商”,只能登录授权层,以此将用户与客户端区分开来。”客户端”登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。
“客户端”登录授权层以后,”服务提供商”根据令牌的权限范围和有效期,向”客户端”开放用户储存的资料。
于是上述过程就变成了以下步骤:
- 我先去服务提供商那里登记备案,我叫魁斯哒浮-优艾斯题壁,我的编号是9527,我家住www.lichengyuan.com
- 我将团长引导到授权页面,上面写着我的名字,我要申请干哪些事的权限,这个权限就限制了我看团长其他邮件的权力,就解决了问题2
- 团长一看是我,确认ok,服务提供商就会将一个临时的code发给我家,www.lichengyuan.com/room201,所以即使有人冒充我,这个code还是发不到他手里去
- 我用code去服务提供商换取访问令牌后,就可以访问我申请权限范围内的资源
在上述过程中,团长从没有告诉我任何人密码,解决了问题1;团长可以随时去服务提供商那里解除我的授权,而不影响其他助理,解决了问题3;由于我没有拿到团长的密码,自然也泄露不了团长的密码,即使访问令牌被泄露,由于其失效短,权限有限,其危害性也相对较小。
授权流程
以常见的微信授权登录为例,描述一个相对完整的OAuth2.0授权流程
用户访问客户端,后者将前者导向认证服务器
- response_type:表示授权类型,必选项,此处的值固定为”code”
- client_id:表示客户端的ID,必选项
- redirect_uri:表示重定向URI,可选项
- scope:表示申请的权限范围,可选项(解决问题2)
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值(这是一个给client开发者自投自抢的参数)
用户选择是否给予客户端授权(选‘是’继续流程)
这里用户将在授权服务器的页面上,看到请求授权的客户端是谁,请求哪些权限,而这两个关键信息,客户端是无法撒谎的
认证服务器将用户导向客户端事先指定的”重定向URI”(redirection URI),同时附上一个授权码
用户确认授权后,认证服务器将回应客户端的url,例如:
http://www.client.com/callback?code=CODE&state=xyz
这个url中:
- code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
客户端收到授权码,附上早先的”重定向URI”,向认证服务器申请令牌。
这一步是在客户端的后台的服务器上完成的,对用户不可见
例:
http://mp.weixin.com/authorize?grant_type=authorization_code&code=CODE&redirect_uri=http://www.client.com/callback
- grant_type:表示使用的授权模式,必选项,此处的值固定为”authorization_code”。
- code:表示上一步获得的授权码,必选项。
- redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
- client_id:表示客户端ID,必选项。
认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
refresh_token的作用
如果用户访问的时候,客户端的”访问令牌”已经过期,则需要使用”更新令牌”申请一个新的访问令牌。
由于access_token作为客户端的准入令牌,可能在访问过程中被泄露,于是OAuth在设计上,access_token的有效时间通常不会太长,以微信为例,应该是2小时,所以access_token被泄露的危害被控制在一定范围内。(解决问题4)
而refresh_token只在首次获得和请求刷新”访问令牌”时才会在网络中出现,其他时间都是保存在客户端内部,很难被泄露,所以有效时间可以相对较长,这样既保证了安全性,也避免了因为”访问令牌”失效,而需要让用户一直去点授权的麻烦。
需要实现OAuth的场景
如果你的应用,保存了大量的用户数据,又准备接入大量的第三方应用以实现平台化,那么就必须要实现OAuth2.0授权机制。
至于具体的实现途径,后续我会尝试开源一个框架来实现。