Cuuube / blog

blog on Mirror
1 stars 0 forks source link

[oauth]对oauth2登陆的总结 #59

Open Cuuube opened 6 years ago

Cuuube commented 6 years ago

对oauth2登陆的总结

前言

这周项目上用到了需要获取第三方用户权限来授权登陆我们网站。用到的技术是oauth2。

一遍看文档,一遍写demo,花了一天终于搞清了其中奥妙。所以赶紧记录下来,给健忘的自己。

简介

oauth是个什么呢?

推荐阅读:理解OAuth 2.0 —— 阮一峰

我的这篇文章也是从阮大大那里反刍而成。并且不一定有阮大大写的全面且通俗易懂。希望大家一定看看。

简单来说,oauth2.0,规范了一套授权的流程。它是被广泛验证而且应用的。如果大家都按照这个流程来执行验证,可以减少很多代码量。

oauth2.0的流程

前面也说了,oauth2.0只是一套流程和接口的规范。

所以毫不客气的说,oauth就是一堆api调来调去,只要你会服务器端http请求,和一点浏览器前端知识,你就能自己完成一套从授权者到请求授权者的全部代码。

那么我们现在来扒一扒都有哪些api,怎么调。

在调用之前,需要先声明几个角色:

我们就以第三方登陆为例,设定以下场景:

网站A接入了网站B,允许用户在网站A上点击“用XX登陆”来使用用户在网站B上的身份信息来登陆网站A(如同一般网站上的用QQ登陆)。

此时网站A扮演Requester,网站B扮演DataOwner。用户自己是User。

开始展开调用。

第一步:用户点击网站A上的XX登陆按钮

用户点击了网站A上的XX登陆。一般而言,会先跳转到网站A上的某条路由。

/oauth/login/B

然后此路由中代码收到消息:有匿名用户希望用用户在B上的资料登陆。

按照规则,网站A开始扮演Requester的角色。他需要联系DataOwner,开始请求数据。

第二步: Requester向DataOwner索要User的身份授权

此请求一般为redirect,并且通常请求uri中带有authorize

直接拿阮大大文中的例子

GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
        &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1

发送的字段一般含有如下:

  • response_type:表示授权类型,必选项,此处的值固定为"code"
  • client_id:表示客户端的ID,必选项
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
  • redirect_uri:表示重定向URI,可选项
  • scope:表示申请的权限范围,可选项

其中client_id是DataOwner提前商定给Requester的一个定值,代表Requester方有获取DataOwner中用户内容的权限。

此时,用户界面已经被重定向到DataOwner服务器那里。此阶段对用户不可见,用户那里只看到浏览器url变了,然后在转圈圈。

第三步:DataOwner让User输入身份信息,确认身份

此时,DataOwner处理完毕上一步,发送重定向给用户,到自己的登陆页面。

用户会看到界面变为了网站B的登陆页面。需要输入自己在网站B的账户密码。

当用户输入完毕后,便离开了网站B的登陆页,暂时又开始转圈圈。

第四步:DataOwner确认User身份,确认User同意将身份信息给Requester使用,于是向Requester发送请求,带上用户授权码

而DataOwner角色此时收到了用户登陆信息,确认完毕电脑前这个生物是自己的用户,会生成一个字符串,作为用户授权码

还记得第二步吗?Requester请求authorize接口时,带了一个redirect_uri字段。此时它有用了。

DataOwner会用get请求,请求redirect_uri给的uri。用这种方式,把信息传回给Requester。

这个请求会带上如下字段:

  • code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

此时对于用户而言,刚刚输入完毕B网站的登陆信息后,被跳转到了之前的网站A。然后再等待响应。这状态一直持续的本文的第十步。

第五步:Requester收到用户授权码,向DataOwner请求令牌(token)。

Requester需要提前写好这条redirect_uri的callback路由,以接收code和state。

当callback路由接收到之后,就可以向DataOwner请求令牌(token)了。

请求令牌的uri通常带有token字样。

例:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

这次索取token的请求,通常带有如下参数:

  • grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
  • code:表示上一步获得的授权码,必选项。
  • redirect_uri:表示重定向URI,必选项,且必须与上一步的该参数值保持一致。
  • client_id:表示客户端ID,必选项。

很容易理解。

第六步:DataOwner验证用户授权码的真伪,向Requester响应令牌(token)

DataOwner收到请求,会验证一下用户授权码(code)的真伪,是不是由自己发出的。当验证成功,就可以响应了。token的响应通常是如下字段:

  • access_token:表示访问令牌,必选项。
  • token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
  • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
  • refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。

DataOwner角色注意,响应头中必须设置本响应不允许缓存。因为access_token通常是一次性的。被缓存会影响下次的请求。

第七步:Requester收到令牌,带上令牌向DataOwner请求用户数据

现在Requester收到了token了。已经证明了自身的纯洁,和用户的意愿。既然你来我往都自愿,那就可以大大方方地索取用户的数据了。

向DataOwner的用户数据路由请求就不是oauth2.0负责规范的范围了。但一定要带上刚刚获取的token吧?下面是个简单的例子:

POST /user_info?access_token=xxxxxxxxxxxxxxx HTTP/1.1

第八步:DataOwner验证令牌,将Requester请求的用户信息响应过去

DataOwner验证自己发送的令牌真伪。如属真,则响应用户信息。

至于响应哪些用户信息,就通常是各家不同,看DataOwner角色提供的接入文档了。

第九步:Requester收到用户信息,执行登陆/注册操作

得到了用户的信息,这一步也没什么好说的。可以把用户信息存进自己的数据库注册用户。

(如目的不是第三方登陆,只是请求一部分资料,则可以拿资料接下来的事。)

第十步:Requester将该用户登陆/注册完毕,重定向User的页面,此时User发现自己已经登陆了。完毕

恭喜恭喜,用户终于看到页面动了,页面转到网站A,并且此时自己已经被注册为网站A的会员了。

终于达成了用户用网站B的信息来注册网站A的会员这一战略目的。

最后——感谢阮一峰大大!