nodejs实现OAuth2.0授权服务认证


Posted in NodeJs onDecember 27, 2017

OAuth是一种开发授权的网络标准,全拼为open authorization,即开放式授权,最新的协议版本是2.0。

举个栗子:

有一个"云冲印"的网站,可以将用户储存在Google的照片,冲印出来。用户为了使用该服务,必须让"云冲印"读取自己储存在Google上的照片。

传统方法是,用户将自己的Google用户名和密码,告诉"云冲印",后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点。

  1. "云冲印"为了后续的服务,会保存用户的密码,这样很不安全。
  2. Google不得不部署密码登录,而我们知道,单纯的密码登录并不安全。
  3. "云冲印"拥有了获取用户储存在Google所有资料的权力,用户没法限制"云冲印"获得授权的范围和有效期。
  4. 用户只有修改密码,才能收回赋予"云冲印"的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。
  5. 只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。

所以OAuth就诞生了!

  1. Third-party application:第三方应用程序,本文中又称"客户端"(client),即上一节例子中的"云冲印"。
  2. HTTP service:HTTP服务提供商,本文中简称"服务提供商",即上一节例子中的Google。
  3. Resource Owner:资源所有者,本文中又称"用户"(user)。
  4. User Agent:用户代理,本文中就是指浏览器。
  5. Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。
  6. Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。

登录层提供令牌(token)的生成,其中token包括:有效期、权限范围。客户端拿到token去访问受限资源。

  1. access_token:请求资源时需要携带的token,即访问token。
  2. refresh_token:刷新token,如果access_token过期,可以使用该token获取一份新的access_token和新的refresh_token。一般refresh_token时效性较长,比如一年,而access_token时效性较短,比如几分钟。
  3. 权限范围:即指定客户端可以获取的资源权限范围。

OAuth授权模式

OAuth有四种授权模式,分别为:

  1. 授权码模式(authorization code)
  2. 简化模式(implicit)
  3. 密码模式(resource owner password credentials)
  4. 客户端模式(client credentials)

1、授权码模式

授权码模式是最为严密的授权模式,整体流程为:浏览器携带必要信息至授权页面,正常登录成功后,返回一个code(授权码),客户端拿到code后在后台获取拿code换取token。

nodejs实现OAuth2.0授权服务认证

nodejs实现OAuth2.0授权服务认证

2、密码模式

密码模式,简单地理解即为使用用户名密码等参数获取access_token,它的步骤如下:

  1. 用户向客户端提供用户名和密码。
  2. 客户端将用户名和密码发给认证服务器,向后者请求令牌。
  3. 认证服务器确认无误后,向客户端提供访问令牌。

nodejs实现OAuth2.0授权服务认证

3、refresh_token的应用

refresh_token被用来获取新的access_token和refresh_token,使用方式简单如下:

nodejs实现OAuth2.0授权服务认证

refresh_token无效:

nodejs实现OAuth2.0授权服务认证

使用nodejs实现OAuth授权服务

技术栈:

  1. nodejs + eggjs
  2. eggjs-oAuth-server插件

具体可以参考:
https://github.com/Azard/egg-oauth2-server
https://cnodejs.org/topic/592b2aedba8670562a40f60b

1、code grant模式测试及单点登录实现

这里我们构建两个站点,一个是7001端口(授权服务),一个是7002端口(客户端),授权模式为code grant。

首先是客户端登录页:

nodejs实现OAuth2.0授权服务认证

单击按钮后直接登录:

nodejs实现OAuth2.0授权服务认证

可以发现,浏览器重定向到授权服务地址,并携带了response_type、client_id、redirect_uri三个参数,登录成功后,浏览器会重定向到redirect_uri指定的地址,即这里的*http://127.0.0.1:7002/auth/redirect*:

如下为授权服务的登录页写法

<form action="/oauth2/authorize?{{query}}" id="form1" name="f" method="post">
  <div class="input_outer">
    <span class="u_user"></span>
    <input name="username" class="text" style="color: #FFFFFF !important" type="text" placeholder="请输入账户">
  </div>
  <div class="input_outer">
    <span class="us_uer"></span>
    <input name="password" class="text" style="color: #FFFFFF !important; position:absolute; z-index:100;"value="" type="password" placeholder="请输入密码">
  </div>
  <div class="mb2"><a class="act-but submit" href="javascript:;" rel="external nofollow" onclick="document.getElementById('form1').submit()" style="color: #FFFFFF">登录</a></div>
</form>

这里的${query}即为客户端登录重定向携带的完整query,然后是/oauth2/authorize路由的写法:

app.all('/oauth2/authorize', app.oAuth2Server.authorize());// 获取授权码

这里调用app.oAuth2Server.authorize()时,插件会自动执行重定向操作,首先是重定向到客户端指定地址,客户端拿到code和state后,再去授权层获取token:

async redirect(){
  // 服务端重定向过来的
  console.log(this.ctx.query)
  const result = await this.ctx.curl('http://127.0.0.1:7001/users/token', {
   dataType: 'json',
   // contentType: 'application/x-www-form-urlencoded', // 默认格式
   method: 'POST',
   timeout: 3000,
   data: {
    grant_type: 'authorization_code',
    code: this.ctx.query.code,
    state: this.ctx.query.state,
    client_id: client_id,
    client_secret: client_secret,
    redirect_uri: redirect_uri,
   }
  });
  this.ctx.body = result.data;
 }

获取到token后正常返回:

nodejs实现OAuth2.0授权服务认证

2、password grant模式测试

首先使用username、password获取access_token:

nodejs实现OAuth2.0授权服务认证

用户名或密码错误时返回:

nodejs实现OAuth2.0授权服务认证

使用token获取授权资源正常返回:

nodejs实现OAuth2.0授权服务认证

以上内容完整源码参考:https://github.com/caiya/eggjs-oAuth2-server

总结

  1. OAuth实际使用时要上https,包括客户端和授权服务端
  2. 授权服务可以使用私钥签名,客户端使用公钥验证,从而保证数据安全性

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
NodeJs的优势和适合开发的程序
Aug 14 NodeJs
基于NodeJS+MongoDB+AngularJS+Bootstrap开发书店案例分析
Jan 12 NodeJs
详解nodejs微信公众号开发——5.素材管理接口
Apr 11 NodeJs
详解nodeJS之二进制buffer对象
Jun 03 NodeJs
docker中编译nodejs并使用nginx启动
Jun 23 NodeJs
理解nodejs的stream和pipe机制的原理和实现
Aug 12 NodeJs
nodejs实现截取上传视频中一帧作为预览图片
Dec 10 NodeJs
nodejs实现超简单生成二维码的方法
Mar 17 NodeJs
NodeJS安装图文教程
Apr 19 NodeJs
详解Nodejs内存治理
May 13 NodeJs
纯异步nodejs文件夹(目录)复制功能
Sep 03 NodeJs
NodeJS http模块用法示例【创建web服务器/客户端】
Nov 05 NodeJs
使用nodejs+express实现简单的文件上传功能
Dec 27 #NodeJs
nodejs超出最大的调用栈错误问题
Dec 27 #NodeJs
nodejs实现简单的gulp打包
Dec 21 #NodeJs
nodejs调取微信收货地址的方法
Dec 20 #NodeJs
基于nodejs实现微信支付功能
Dec 20 #NodeJs
nodeJS微信分享
Dec 20 #NodeJs
NodeJS爬虫实例之糗事百科
Dec 14 #NodeJs
You might like
探讨:如何使用PhpDocumentor生成文档
2013/06/25 PHP
对淘宝URL中ID提取的PHP代码
2013/09/01 PHP
PHP使用xmllint命令处理xml与html的方法
2014/12/15 PHP
PHP记录页面停留时间的方法
2016/03/30 PHP
Yii2 GridView实现列表页直接修改数据的方法
2016/05/16 PHP
php实现的中文分词类完整实例
2017/02/06 PHP
PHP实现多级分类生成树的方法示例
2017/02/07 PHP
在网页中屏蔽快捷键
2006/09/06 Javascript
js form 验证函数 当前比较流行的错误提示
2009/06/23 Javascript
jfreechart插件将数据展示成饼状图、柱状图和折线图
2015/04/13 Javascript
举例详解AngularJS中ngShow和ngHide的使用方法
2015/06/19 Javascript
使用vue.js制作分页组件
2016/06/27 Javascript
seajs学习教程之基础篇
2016/10/20 Javascript
JS实现搜索关键词的智能提示功能
2017/07/07 Javascript
JS实现的全排列组合算法示例
2017/10/09 Javascript
实现div内部滚动条滚动到底部和顶部的代码
2017/11/15 Javascript
nodejs分离html文件里面的js和css的方法
2019/04/09 NodeJs
vue 表单之通过v-model绑定单选按钮radio
2019/05/13 Javascript
layer设置maxWidth及maxHeight解决方案
2019/07/26 Javascript
JS扁平化输出数组的2种方法解析
2019/09/17 Javascript
Vue 设置axios请求格式为form-data的操作步骤
2019/10/29 Javascript
vue组件创建的三种方式小结
2020/02/03 Javascript
python简单获取本机计算机名和IP地址的方法
2015/06/03 Python
Django框架中数据的连锁查询和限制返回数据的方法
2015/07/17 Python
基于python中staticmethod和classmethod的区别(详解)
2017/10/24 Python
python操作excel的方法(xlsxwriter包的使用)
2018/06/11 Python
python 实现将txt文件多行合并为一行并将中间的空格去掉方法
2018/12/20 Python
如何利用Pyecharts可视化微信好友
2019/07/04 Python
Python对接 xray 和微信实现自动告警
2019/09/17 Python
Anconda环境下Vscode安装Python的方法详解
2020/03/29 Python
tensorflow 2.0模式下训练的模型转成 tf1.x 版本的pb模型实例
2020/06/22 Python
AmazeUi Tree(树形结构) 应用小结
2020/08/17 HTML / CSS
迪斯尼假期(欧洲、中东及非洲):Disney Holidays EMEA
2021/02/15 全球购物
Prototype是怎么扩展DOM的
2014/10/01 面试题
写作之关于描写老人的好段摘抄
2019/11/14 职场文书
Python装饰器的练习题
2021/11/23 Python