一、概念及场景
Oauth2.0(Open Authorization)协议是一个关于授权(authorization)的开放网络标准,是目前应用最广泛的标准之一。简单讲,所谓授权指的是我们通过微信、github等帐号的方式登录比如V2EX、知乎、简书这样的网站或应用。目前包括github、facebook、twitter、微信、微博、QQ等社交工具都集成了Oauth2.0协议以供第三方应用程序使用,实现一个社交帐号打通所有应用。
停下来想一想,刷朋友圈的时候是不是经常遇到这样的情况呢( ̄▽ ̄),下面我将结合自己的开发和校招经历,分享一下在Oauth2.0的授权码模式下进行第三方应用程序开发的过程。
二、授权的角色
1、Third-party application:第三方应用程序,即上面提到的V2EX、知乎、简书
2、Resource Owner:资源所有者,也就是持有微信、github帐号的用户。
3、User Agent:用户代理,比如浏览器这样的工具。
4、Authorization server:认证服务器,也就是微信、github配置的专门用来处理认证的服务器。
5、Resource server:资源服务器,即微信、github存放用户生成的资源如帐号、头像、昵称等的服务器。需要注意的是它与认证服务器,可以是同一台服务器,也可以是不同的服务器
三、授权的模式
客户端必须得到用户的授权(authorization grant),才能获得用户获取资源比如微信头像、昵称等的令牌(access token)。OAuth 2.0定义了四种授权方式。
1、授权码模式(authorization code)
2、简化模式(implicit)
3、密码模式(resource owner password credentials)
4、客户端模式(client credentials)
其中,授权码模式(authorization code)是功能最完整、流程最严密的授权模式。
四、授权码(Authorization Code)模式
在开发准备阶段,需要从服务提供商开发者平台(以金数据为例)注册,取得用以获得授权码(code)的授权域(授权的网址)、应用ID(client_id)和对应密钥(client_secret),并配置我们要开发的第三方应用的回调地址(redirect_uri)、授权范围(scope);这就相当于校招的时候网申、考核的过程。
当我们毕业参加招聘时一般会经历下面几个过程:
报名 ---->参加笔试面试---->公司发放offer---->拿到offer后进入公司拿到工牌---->有了工牌就可以使用公司的资源
其实整个Oauth2.0的授权码模式和这个很相似。
(1)流程示意图:
(2)完整的过程:
第一步,带上这些参数向认证服务器(Authorization server)发送授权请求,认证服务器收到请求,验证参数,若成功,弹出登录页面或授权页面(比如上图的截图),若参数不一致,弹出错误。这一步好比校招的时候参加面试(。・ω・。)
*请求参数包括应用ID(client_id)、回调地址(redirect_uri)、授权范围(scope)、response_type(Oauth2.0为code)、状态(state)等
第二步,资源所有者(用户)确认授权,认证服务器携带授权码(code)和状态参数(state)返回请求到相应的回调地址(redirect_uri)。可以类比校招的时候参公司给你发了offer (°∀°)ノ
第三步,拿到了offer后,哦不,拿到了授权码(code),就可以向认证服务器请求令牌(access token),认证服务器会返回生成的令牌(access token)及刷新令牌时用到的(refresh token)等参数。发工牌啦 ("▔□▔)/
*请求参数包括应用ID(client_id)、对应密钥(client_secret)、、上一步获得的授权码(code)、回调地址(redirect_uri)、授权模式(grant_type,这里是authorization_code)、授权范围(scope)、上一步获得的状态(state)等
第四步,用户代理(浏览器)携带令牌(access token)向资源服务器发送请求,访问在第三方应用程序授权范围(scope)内的资源,比如微信名称、头像等。拿到了工牌之后可以享受公司的资源 (⌒▽⌒)
五、那些坑
1、回调地址必须一致;
有时候我们在测试服务器时授权是正常的,在产品服务器上就不行,因为回调地址是唯一的,且严格一致的。
2、refresh token的过期时间问题;
因为每个令牌(access token)都是有过期时间(expires_in)的,一般默认为7200s,也就是2h,令牌过期后如果进行访问资源,服务器会返回403(未授权)错误,所以令牌必须即时提前刷新。
为了避免重新获得令牌的过程刚开始一样复杂,Oauth2.0规定每个令牌(access token)生成时必须同时生成过期时间(expires_in)和刷新令牌(refresh token),在任意时间,使用刷新令牌(refresh token)可以向认证服务器请求生成一个新的令牌(access token),此时原有的令牌和刷新令牌失效!所以如果你的本地环境和测试服务器使用的是同一个令牌时,当本地环境提前刷新token后,将造成你的测试服务器无法继续刷新token;
刷新token的2种方式:
1、主动式:提前存好令牌(access token)的过期时间(令牌过期时间=获得accesstoken的时间+过期时间(expires_in)- 冗余时间t)。在服务器运行crontab定时任务, 每隔小于t的时间,检查数据库中所有用户token的令牌过期时间是否大于当前时间,自动刷新;这样的好处是保证每时每刻token都是有效的,但是对于服务器有一定负载;
2、被动式:(令牌过期时间=获得access token的时间+过期时间(expires_in)。当要使用当前令牌(access token)时,检查该令牌过期时间是否大于当前时间,进行刷新;这是最简单的做法,能够节省资源,但是有一定几率会造成用户体验过慢,毕竟刷新token需要时间;不推荐被动式刷新。
以上是我在进行金数据应用中心的抽奖应用的开发过程中的一些体会,当然,目前基本上所有的框架都封装了Oauth2.0的库,大家只需要按照文档使用这些库,如果大家是Rails爱好者,给大家推荐一下Omniauth,如果大家是PHP Laravel的开发者,给大家推荐一下Laravel Socialite这个库,当然,像金数据这样的纯api有很多复杂的请求,大家可以参考我做的集成SocialiteForJinshuju。
欢迎大家能分享更多的内容,哔哩哔哩 - ( ゜- ゜)つロ 乾杯~
参考: