OAuth2.0 知多少

OAuth2.0 知多少
原文:OAuth2.0 知多少

1. 引言

周末逛简书,看了一篇写的极好的文章,点击大红心点赞,就直接给我跳转到登录界面了,原来点赞是需要登录的。

简书登录界面

可是没有我并没有简书账号,一直使用的QQ的集成登录。下面有一排社交登录按钮,我们可以用第三方社交账号登陆即可。点击QQ图标,就给我跳转到了QQ登录授权页面,如下图:

QQ登录授权页面

从图片上我们可以看到主要包括两个部分,一个是左边的用户登录,一个是右边告知简书将获取哪些权限。输入QQ账号和密码,点击授权并登录,就成功登录到简书了,并成功获取到了我QQ的账号和昵称,如下图:

简书成功获取到QQ昵称和头像

简书集成的社交登录,大大简化了我们的注册登录流程,真是一号在手上网无忧啊。
这看似简单的集成,但背后的技术原理『OAuth2.0』可没那么简单,那我们废话不多说,一探究竟吧。

2. OAuth 2.0

OAuth 2.0是用于授权的行业标准协议。OAuth 2.0取代了在2006年创建的原始OAuth协议上所做的工作。OAuth 2.0专注于客户端开发人员的简单性,同时为Web应用程序,桌面应用程序,手机和客厅设备提供特定的授权流程。

在传统的client-server认证模型中,客户端请求访问服务器上受限的资源(protected resource),需要通过使用资源所有者(resource owner)的凭证在服务器上进行认证。为了支持第三方应用程序访问受限资源,资源所有者需要向第三方应用共享其凭证。这就会造成以下问题:

  1. 第三方应用为了后续使用,会存储资源所有者的凭证主要是密码。
  2. 服务端需要支持密码认证,尽管密码认证不安全。
  3. 第三方应用获得对资源的过度访问而不仅局限于受限资源,且资源所有者没有办法对其进行限制。
  4. 资源所有者无法收回权限,除非修改密码。
  5. 如果第三方应用的密码被破解,就会导致所有被该密码保护的数据被泄露。

想一想这样一个场景,如果简书是直接使用QQ用户名密码登录,简书就很有可能会为了后续业务的需要而擅自保存QQ用户名及密码,简书只要拿到了QQ用户名密码就可以访问不仅仅QQ昵称、头像等信息,甚至可以获取到QQ用户的所有通讯录列表。如果简书的账号密码泄露,就会直接影响到QQ数据的安全。这是一个可怕的问题。

所以OAuth应运而生,来解决这一问题。

3. OAuth 2.0授权流程

下面我们就以简书使用QQ授权登录为例,来捋一捋OAuth 2.0的流程。
先来看看OAuth 2.0的流程,如下图所示:
OAuth 2.0授权流程

这里面主要包含四个角色:

  1. Client:需要授权的客户端,本文中就是【简书】。
  2. Resource Owner:资源所有者,在本文中你可能会以为是 QQ,但要想清楚,QQ是属于个人的,所以在本文中资源所有者是指【QQ用户】。
  3. Authorization Server:认证服务器,本文中特指【QQ互联平台】。
  4. Resource Server:资源服务器,顾名思义,用来专门保存资源的服务器,接受通过访问令牌进行访问。本文特指【QQ用户信息中心】。

3.1. 第一步:引导用户到认证服务器

圣杰打开简书网页,简书跳转到登录界面,要求用户登录。可是圣杰未在简书注册帐号,所以就点击了QQ图标,使用QQ帐号进行集成登录。跳转到QQ登录界面后,QQ要求用户授权。
这一步中简书主要做了这样一件事就是引导用户到认证服务器。
很显然【QQ互联平台】就是认证服务器。

如何引导?当然是页面跳转。
那认证服务器如何知道是简书过来的认证请求?
当然是传参。
那需要传递哪些参数呢?

  • response_type:表示响应类型,必选项,此处的值固定为"code";
  • client_id:表示客户端的ID,用来标志授权请求的来源,必选项;
  • redirect_uri:成功授权后的回调地址;
  • scope:表示申请的权限范围,可选项;
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

咱们看看简书实际发送的授权请求Url是:
https://graph.qq.com/oauth2.0/authorize?client_id=100410602 &redirect_uri=http://www.jianshu.com/users/auth/qq_connect/callback &response_type=code &state=bb38108d1aaf567c72da0f1167e87142d0e20cb2bb24ec5a

无图无真相,咱们看看控制台的网络监控:

简书跳转到QQ登录的认证请求

如图所示,除了scope参数外,其他四个参数均有传参。
此时你可能唯一对state参数比较迷惑,传递一个state参数,认证服务器会原封不动返回,那还干嘛要传递state参数呢?

我的理解是,简书用一个guid加长版字符串来唯一标识一个授权请求。这样才会正确获取授权服务器返回的授权码。

这里你可能会问了,既然我知道了这些参数,我岂不是可以伪造简书认证请求,修改redirect_uri参数跳转到个人的网站,然后不就可以获取QQ授权?

跟我一样太傻太天真,简书在QQ互联平台申请时肯定已经预留备案了要跳转返回的URL。QQ互联平台在收到简书的授权请求时肯定会验证回调Url的。

3.2. 第二步:用户同意为第三方客户端授权

这一步,对于用户来说,只需要使用资源所有者(QQ)的用户名密码登录,并同意授权即可。点击授权并登录后,授权服务器首先会post一个请求回服务器进行用户认证,认证通过后授权服务器会生成一个授权码,然后服务器根据授权请求的redirect_uri进行跳转,并返回授权码code和授权请求中传递的state
这里要注意的是:授权码有一个短暂的时效

无图无真相,咱们还是看一下控制台网络监控:

用户授权并登录

从图中即可验证我们上面所说,最终跳转回简书的Url为:
http://www.jianshu.com/users/auth/qq_connect/callback?code=093B9307E38DC5A2C3AD147B150F2AB3 &state=bb38108d1aaf567c72da0f1167e87142d0e20cb2bb24ec5a
和之前的授权请求URL进行对比,可以发现redirect_uristate完全一致。
code=093B9307E38DC5A2C3AD147B150F2AB3就是返回的授权码。

3.3. 第三步:使用授权码向认证服务器申请令牌

从这一步开始,对于用户来说是察觉不到的。简书后台默默的在做后续的工作。

简书拿到QQ互联平台返回的授权码后,需要根据授权码再次向认证服务器申请令牌(access token)。
到这里有必要再理清两个概念:

  • 授权码(Authorization Code):相当于授权服务器口头告诉简书,用户同意授权使用他的QQ登录简书了。
  • 令牌(Access Token):相当于临时身份证。

那如何申请令牌呢?
简书需要后台发送一个get请求到认证服务器(QQ互联平台)。
那要携带哪些必要信息呢?
是的,要携带以下参数:

  • grant_type:表示授权类型,此处的值固定为"authorization_code",必选项;
  • client_id:表示从QQ互联平台申请到的客户端ID,用来标志请求的来源,必选项;
  • client_secret:这个是从QQ互联平台申请到的客户端认证密钥,机密信息十分重要,必选项;
  • redirect_uri:成功申请到令牌后的回调地址;
  • code:上一步申请到的授权码。

根据以上信息我们可以模拟一个申请AccessToken的请求:
https://graph.qq.com/oauth2.0/token?client_id=100410602 &client_secret=123456jianshu &redirect_uri=http://www.jianshu.com/users/auth/qq_connect/callback &grant_type=authorization_code &code=093B9307E38DC5A2C3AD147B150F2AB3

发送完该请求后,认证服务器验证通过后就会发放令牌,并返回到简书后台,其中应该包含以下信息:

  • access_token:令牌
  • expires_in:access token的有效期,单位为秒。
  • refresh_token:在授权自动续期步骤中,获取新的Access_Token时需要提供的参数。

同样,我们可以模拟出一个返回的token:
http://www.jianshu.com/users/auth/qq_connect/callback?access_token=548ADF2D5E1C5E88H4JH15FKUN51F &expires_in=36000&refresh_token=53AD68JH834HHJF9J349FJADF3

这个时候简书还有一件事情要做,就是把用户token写到cookie里,进行用户登录状态的维持。咱们还是打开控制器验证一下。

保存token到cookie

从图中可以看出简书把用户token保存在名为remember_user_token的cookie里。
不用打cookie的歪主意了,肯定是加密了的。
可以尝试下手动把remember_user_token这条cookie删除,保证刷新界面后需要你重新登录简书。

3.4. 第四步:向资源服务器申请资源

有了token,向资源服务器提供的资源接口发送一个get请求不就行了,资源服务器校验令牌无误,就会向简书返回资源(QQ用户信息)。

同样咱们也来模拟一个使用token请求QQ用户基本信息资源的URL:
https://graph.qq.com/user/get_user_info?client_id=100410602 &qq=2098769873 &access_token=548ADF2D5E1C5E88H4JH15FKUN51F

到这一步OAuth2.0的流程可以说是结束了,但是对于简书来说还有重要的事情要做。那就是:
拿到token、reresh_token和用户数据这么重要的东西不存数据库傻呀?

3.5. 第五步:令牌延期(刷新)

你肯定对第四步返回的refresh_token比较好奇。
它是用来对令牌进行延期(刷新)的。为什么会有两种说法呢,因为可能认证服务器会重新生成一个令牌,也有可能
对过期的令牌进行延期。

比如说,QQ互联平台为了安全性考虑,返回的access_token是有时间限制的,假如用户某天不想授权了呢,总不能给了个access_token你几年后还能用吧。我们上面模拟返回的令牌有效期为10小时。10小时后,用户打开浏览器逛简书,浏览器中用户的token对应的cookie已过期。简书发现浏览器没有携带token信息过来,就明白token失效了,需要重新向认证平台申请授权。如果让用户再点击QQ进行登录授权,这明显用户体验不好。咋搞呢?refresh_token就派上了用场,可以直接跳过前面申请授权码的步骤,当发现token失效了,简书从浏览器携带的cookie中的sessionid找到存储在数据库中的refresh_token,然后再使用refresh_token进行token续期(刷新)。

那用refresh_token进行token续期需要怎么做呢?
同样需要向认证服务器发送一个get请求。
需要哪些参数?

  • grant_type:表示授权类型,此处的值固定为"refresh_token",必选项;
  • client_id:表示从QQ互联平台申请到的客户端ID,用来标志请求的来源,必选项;
  • client_secret:这个是从QQ互联平台申请到的客户端认证密钥,机密信息十分重要,必选项;
  • refresh_token:即申请令牌返回的refresh_token。

根据上述信息,我们又可以模拟一个令牌刷新的URL:
https://graph.qq.com/oauth2.0/token?client_id=100410602 &client_secret=123456jianshu &redirect_uri=http://www.jianshu.com/users/auth/qq_connect/callback &grant_type=refresh_token &refresh_token=53AD68JH834HHJF9J349FJADF3
那返回的结果呢?
和第四步返回的结果一样。

这里你可能又有疑问了,那既然每次进行令牌延期后都会重新返回一个refresh_token,那岂不是我可以使用refresh_token无限延期?
天真如我啊,refresh_token也是有过期时间的。而这个过期时间具体是由认证服务器决定的。
一般来说refresh_token的过期时间要大于access_token的过期时间。只有这样,access_token过期时,才可以使用refresh_token进行令牌延期(刷新)。

举个简单例子:
假设简书从QQ互联平台默认获取到的access_token的有效期是1天,refresh_token的有效期为一周。

用户今天使用QQ登录授权后,过了两天再去逛简书,简书发现token失效,立马用refresh_token刷新令牌,默默的完成了授权的延期。
假如用户隔了两周再去逛简书,简书一核对,access_tokenrefresh_token全都失效,就只能乖乖引导用户到授权页面重新授权,也就是回到OAuth2.0的第一步。

4.0 总结

本文以简书通过QQ进行授权登录为例,对OAuth2.0 的授权流程进行了梳理,希望通读此文,对你有所帮助。

如果对OAuth2.0有所了解的话,你应该明白本文其实是对OAuth2.0中授权码模式授权方式的讲解。

如果想了解OAuth2.0其他几种授权方式,建议参考理解OAuth 2.0 - 阮一峰的网络日志。

posted on 2018-12-25 10:59 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/10172722.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/248781.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

五分钟带你摸透 Vue组件及组件通讯

一.组件化开发 组件 (Component) 是 Vue.js 强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代 码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在vue中都是组件化开发的,组件化开发就是把一个完整的…

微信公众号开发-接入

一 首先实现内网穿透,公众号需要连接我们的服务器,内外无法访问,所以先实现自己的内网可以测试时连接外网,下载natapp,选择windows,顺便下载config,ini 配置文件。注册好购买免费的隧道 然后将token写入配置…

Vue 项目上线优化

上线项目的优化 优化上线项目,首先在上线打包时我们通过babel插件将console清除,当然对项目打包后的体积的影响是微乎其微,对项目的入口文件的改善也是很有必要的,因为在开发阶段和上线如果我们使用的是同一入口文件,…

Python并发编程—进程

多任务编程 1.意义: 充分利用计算机多核资源,提高程序的运行效率。 2.实现方案 :多进程 , 多线程 3.并行与并发 并发 : 同时处理多个任务,内核在任务间不断的切换达到好像多个任务被同时执行的效果&#xf…

Vue 脚手架中的.eslintrc.js代码规范 的解决

在我们使用Vue脚手架 创建项目时 尤其是团队共同开发项目时 会按照一个共同的代码规范来编程 创建Vue脚手架中有一个.eslintrc.js格式 但是在编程中我们通常会使用 shiftaltf 进行代码格式化 但是由于格式化后的代码 与Vue中的.eslintrc规范不协调 尤其是 “” ; 以…

前端面试---Vue部分考点梳理

一. Vue的使用 1. Vue的基本使用 指令 插值 插值 表达式 指令 动态属性 v-html 会有XSS风险 会覆盖子组件 computed 和 watch computed 有缓存 data不变则不会重新计算watch 如何深度监听watch 监听引用类型时 拿不到oldVal v-for v-for 和 v-if 不能同时使用:key的值尽量…

.net core实现跨域

什么是跨域在前面已经讲解过了,这里便不再讲解,直接上代码。 一、后台API接口 用.net core创建一个Web API项目负责给前端界面提供数据。 二、前端界面 建立两个MVC项目,模拟不同的ip,在view里面添加按钮调用WEB API提供的接口进行…

TCP/IP简介

TCP/IP简介 OSI的“实现”:TCP/IP参考模型 并不完全符合OSI的七层参考模型,但我们可以理解为OSI的一种实现 TCP/IP协议简述 在很多情况下,它只是利用IP协议进行通信时,所必须用到的协议群的统称,具体来说,I…

Spring-Cloud 学习笔记-(4)负载均衡器Ribbon

目录 Spring-Cloud 学习笔记-(4)负载均衡器Ribbon1、前言2、什么是负载均衡2.1、问题分析2.2、什么是Ribbon3、快速入门3.1、实现方式一3.1.1、修改代码3.2、实现方式二3.2.1、启动类3.2.2、调用代码3.2.3、测试3.2.4、实现原理3.2.5、断点调式3.3、修改…

‘仿微信发表朋友圈’项目中登录功能的业务逻辑

登录功能 手机号验证码都通过后端验证后 返回用户数据 登陆成功 成功后 调用store中的setUser方法 store中的setUser方法 将后端返回的用户信息存储到localStorage中 同时登录成功后服务器会将token自动存入我们的cookie中 有过期时间 在我们请求需要登录的接口时将cookie中的…

kubernetes--配置文件

转载于:https://www.cnblogs.com/caiciadeliliang/p/10993388.html

微信动态中的背景图更换

初衷: 图一中的红框中的部分,作为用户自定义的背景图,如果用户没有上传也会为其自动设置一张背景图,当用户点击时则会出现图二中的选项 ,点击取消则选项消失,点击从相册选择则会跳转本机的相册&#xff0c…

大数据学习——akka自定义RPC

实现 package cn.itcast.akkaimport akka.actor.{Actor, ActorSystem, Props} import akka.actor.Actor.Receive import com.typesafe.config.ConfigFactoryimport scala.collection.mutableimport scala.concurrent.duration._class Master(val host: String, val port: Int) …

从Client应用场景介绍IdentityServer4(一)

从Client应用场景介绍IdentityServer4(一) 原文:从Client应用场景介绍IdentityServer4(一)一、背景 IdentityServer4的介绍将不再叙述,百度下可以找到,且官网的快速入门例子也有翻译的版本。这里主要从Clie…

开发常用代码笔记

Vue 使用moment插件对时间进行格式化(全局设置) 下载插件 npm install moment --save 在main.js中引入插件 import moment from ‘moment’ 在main.js中定义全局过滤器 Vue.filter(dataFilter,function (dataStr,patten YYYY-MM-DD HH:mm:ss) {retur…

微信小程序——账号及开发工具

1. 注册微信小程序账号 点击我进入微信公众平台 进入后点击立即注册 注册成功且登录后进入小程序管理后台 2. 安装开发者工具 点击进入开发文档 进入安装开发工具(稳定版本) 一路默认下一步进行安装 3. 开发者工具的使用 使用注册微信小程序的微信号…

CSS注意的地方

content-box和border-box的区别 2018年02月27日 22:20:16 sulingliang 阅读数:8011盒子模型 盒子宽度:paddingbordercontent-width 盒子高度:paddingbordercontent-height 如图所示 盒子模型content-box 说明:在内容宽度和高度之…

机器学习笔记(6) 线性回归

先从最简单的例子开始,假设我们有一组样本(如下图的一个个黑色的圆点),只有一个特征,如下图,横轴是特征值,纵轴是label。比如横轴是房屋面积,纵轴是房屋价格. 现在我们要做什么呢?我们试图找到一条直线yaxb,可以尽量好的拟合这些点. 你可能要问了,为啥是直线,不是曲…

仿微信朋友圈项目梳理

项目功能简介: 用户通过手机号验证码进行登录和注册 可以浏览动态列表中的所有动态 登录成功后用户可以发表自己的动态 也可以对自己认可欣赏的动态进行点赞和评论 也可以通过动态结识志同道合的朋友 进行聊天和探讨 前端:采用Vue框架搭建 weui进行页面…

echarts鼠标事件以及自定义数据获取

事件添加方法: 对应官网位置:https://www.echartsjs.com/api.html#events 鼠标事件包括 click、dblclick、mousedown、mousemove、mouseup、mouseover、mouseout、globalout、contextmenu。 myChart.on(click, function (params) {console.log(params); …