互联网是一个巨头垄断的市场,市场资源大多被有实力的大公司支配着,比如google、Alibaba、Tencent等等,当我们想用它们的资源时,就需要用到授权。而OAuth 2.0是目前最流行的授权机制,用来授权给第三方应用,从而能够获取到授权方的用户数据信息。OAuth 2.0给第三方应用带来了巨大的便利,使我们的用户信息可以适用于整个互联网,而不需要每个应用都注册自己账户信息。比如在第三方应用中使用微博、微信、QQ账号登录功能,所使用的就是OAuth授权。
第三方应用为了获取授权方的数据信息,可以用授权方的用户账号密码去登录,但是这个作法有个致命的弱点就是,随着授权的第三方接入越来越多,密码就越容易泄露,而且对不同的第三方应用访问资源的权限不好控制。这种使用授权方的用户账号密码去登录的方式一般很少用。而更常用的是使用OAuth授权,**简单说,OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。**相比密码,token有以下的特点
- 1、令牌是短期的,到期会自动失效。
- 2、令牌可以被数据所有者撤销,会立即失效。
- 3、令牌有权限范围(scope)。
第三方可以使用令牌(token)来代替密码访问授权方的资源,那么如何获取令牌(token)呢,OAuth 2.0 的标准中 RFC 6749 文件标准提供四种不同获取授权的方方式。不过在第三方申请令牌(token)之前,必须先到授权方系统进行备案自己的信息,然后拿到授权方给的appId、appSecret,这两个参数通常是要求第三方发送令牌(token)申请时要带上的。
第一种:授权码方式
授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌,这种方式是最常用的流程,安全性也最高。微信公众号开发平台就采用了这种方式,配合其开发文档理解这种授权方式会更深刻,微信网页授权。
这里结合微信网页授权来简要说明一下这种方式,前期准备是注册公众号(备案阶段),拿到微信公众号的appId、appSecret。需要注意的是授权码方式适用于前后端分离的应用,这里的请求都是有后端发起。
发送get请求获取code,下面是微信给出的请求样例
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
此时微信授权方会询问用户是否授权给第三方,当用户确认授权后,会重定向到redirect_uri参数指定的地址,并携带code参数。
发送get请求申请令牌(token),下面是微信给出的请求样例,注意要带上之前获取到的code
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
微信后台验证通过后会重定向请求到redirect_uri参数指定的地址,并携带牌(token)参数。
发送http请求来获取授权方的用户信息,下面是微信给出的请求样例,注意要带上之前获取到的令牌(token)参数
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
第二种:隐藏式
RFC 6749 允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit)。
前端发送get请求到授权方获取token,诸如:
https://b.com/oauth/authorize?response_type=token&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read
授权方返回
https://a.com/callback#token=ACCESS_TOKEN
注意:这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。
第三种:密码式
如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。
发情get请求获取令牌token
https://oauth.b.com/token?grant_type=password&username=USERNAME&password=PASSWORD&client_id=CLIENT_ID
根据返回的令牌token进行数据交互,这种方式暴露了用户自己的用户名/密码信息给第三方,风险比较大。
第四种:凭证式
适用于没有前端的命令行应用,即在命令行下请求令牌,可以使用curl命令等。这种方式用得也还是挺多的,比如百度开放的一些api。
发送请求获取令牌token
https://oauth.b.com/token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
上面 URL 中,
grant_type
参数等于client_credentials
表示采用凭证式,client_id
和client_secret
用来让 授权方确认 第三方 的身份。比如百度开放平台的api都会给一个authkey之类的。
这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。
更新令牌(token)
令牌(token)的有效期比较短,需要用户进行更新授权,如果按获取授权的方式重新获取一次授权会比较浪费资源,OAuth 2.0允许用户自动更新令牌。通常在获取令牌(token)时,授权方不仅仅返回access_token令牌,也返回一个refresh_token令牌,这两个字段一个用于获取数据,另一个用于获取新的令牌,在令牌到期前,我们用refresh_token发送请求去更新令牌即可,示例如下:
发送请求更新令牌
https://b.com/oauth/token?grant_type=refresh_token&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN
微信公众刷新授权的样例
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
使用令牌(token)
令牌(token)使用很简单,在每次调用授权方接口时带上令牌(token)即可,即在HTPP协议头里面的Authorization
字段加上令牌(token)即可。
在httpheader头中加入Authorization字段,有如:
Authorization: YWRtaW46YWRtaW4=
参考微信公众号授权文档吧,我觉得写的很好了。
第三方登录经常使用到,它使得用户跨平台信息交互变得方便,它们的实现基于OAuth 2.0授权。通过授权方式登录,省去了用户密码登录的流程,降低了账户泄露的风险,提升用户信息的安全。记广州于2019-06-28。