node脚手架搭建服务器实现token验证的方法


Posted in Javascript onJanuary 20, 2021

内容

  • 用脚手架快速搭建 node 项目
  • 用 mysql 连接池实现与数据库的交互
  • 用 jsonwebtoken 实现 token 身份验证
  • 综合案例:用简介登录页面实现上述内容

1. 快速搭建 node 项目

我们都知道 express 框架可高效的开发 node 服务器,但对于底层的搭建还要靠自己手写。然而 express-generator 的出现就很好地解决了此问题,它可一键为我们生成项目基本骨架,可谓node 脚手架

1.1 生成项目

①:首先全局安装 express : npm install express -g
②:接着全局安装 express-generator:npm install express-generator -g
③:然后使用命令创建项目: express token_learn(项目名称)

1.2 修改入口文件

对于好多习惯了手撸服务器的人,app.js 总是让人难忘,奈何此骨架中入口文件为 www.js。此时我们可以手动修改app.js 代码,让其成为我们的入口文件

示例:

var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');

const index = require('./routes/index');
const users = require('./routes/users');

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

app.listen(3000, () => console.log('server is run 3000'))

2. 连接mysql 数据库

此处采用连接池的方式进行连接(高效安全)

2.1 创建连接

①:安装 mysql 模块:npm i mysql
②:在项目根目录下配置连接池

首先在项目根目录下创建 util 文件夹,文件夹下创建 bdconfig.js 文件

bdconfig.js

const mysql = require('mysql');

module.exports = {
  mysqlParams: {
    host: 'localhost', //域名
    port: '3306', //端口
    user: 'root', //用户名
    password: 'myroot', //密码
    database: 'nodeapi' //数据库
  },
  sySqlConnect(sql, sqlArr) {
    return new Promise((resolve, reject) => { //用Promise对象将其改造,方便接收数据
      const pool = mysql.createPool(this.mysqlParams);
      pool.getConnection((err, conn) => {
        if (err) {
          reject(err)
        } else {
          conn.query(sql, sqlArr, (err, data) => { //操作数据库
            if (err) {
              reject(err)
            } else {
              resolve(data)
            }
          })
          conn.release() //释放连接
        }
      })
    })
  }
}

2.2 使用连接

使用时只需要传入 sql(sql语句)、sqlArr(参数),通过Promise 改造后可直接用返回值拿到结果

3. token 身份验证

随着web 的发展,session、cookie 的验证方式弊端也愈发突出,此时token孕育而生,token的强大不仅限于其是无状态的,还在于它可以跨域

3.1 实现步骤

①:首先安装 jsonwebtoken 模块:npm i jsonwebtoken
②:接着在项目中使用该模块

const dbConfig = require('../util/dbconfig');
const jwt = require('jsonwebtoken');
const secret = 'login-rule'; //秘钥规则(自定义)

token = async(req, res, next) => { //定义token验证中间件函数(应用于除登录外的每个请求)
  if (req.headers.authorization) {
    const token = req.headers.authorization;
    const { id, username } = jwt.verify(token, secret); // 对token进行解密查找
    let sql = 'select * from test where id=?';
    let sqlArr = [id];
    let result = await dbConfig.sySqlConnect(sql, sqlArr);
    if (result.length === 0) {
      res.status(200).send({ msg: '用户错误' })
      return
    }
    if (username !== result[0].username) {
      res.status(200).send({ msg: '用户错误' })
    } else {
      next()
    }
  } else {
    res.status(200).send({ msg: '无效请求头' })
  }
}

login = async(req, res) => { //定义登录接口(因为这个请求头不携带token,所以引用在token验证中间件之前)
  let { username, password } = req.body;
  let sql = 'select * from test where username=?';
  let sqlArr = [username];
  let result = await dbConfig.sySqlConnect(sql, sqlArr);
  if (result.length) {
    if (password === result[0].password) {
      const { id, username } = result[0];
      //对token进行加密响应个客户端(参数1:传值规则;参数2:加密规则; 参数3:定义时间)
      const token = jwt.sign({ id, username }, secret, { expiresIn: 60 * 60 });
      res.status(200).send({ msg: '登陆成功', token: token, status: 200 });
    } else {
      res.status(200).send({ msg: '登陆失败', status: 422 });
    }
  } else {
    res.status(200).send({ msg: '用户名不存在', status: 401 })
  }
}

// 验证身份中间件
module.exports = {
  token,
  login
}

③:在 app.js 中进行配置

// 写在 app.use() 之后,路由之前
app.use('/users/loginjwt', token.login); //登录接口(无需验证token,所以写在token中间件之前)
app.use(token.token);

4. 案例实现 token

4.1 原理阐述

为确保身份唯一且有效:用户每次发送登录请求且登录成功,服务器端都会响应给用户一个含用户信息(唯一)的加密 token(字符串),此时用户接收到 token,并把 token 存储在 sessionStorage 或 localStorage中(此处为)。同时用户每次发送其他请求时,在请求头中携带本地的 token,服务器端 token验证中间件拦截请求,对 token进行解密,得到用户信息并与数据库比对,信息存在则放行(身份验证成功)。

4.2 效果预览

node脚手架搭建服务器实现token验证的方法

4.3 开始实现

写简洁静态页面,且实现ajax 请求

login.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="../javascripts/jquery.min.js"></script>
  <title>Document</title>
</head>

<body>
  <form id="loginform">
    <input type="text" name="username">
    <input type="password" name="password">
    <input type="submit" value="登录">
  </form>
  <script>
    $(function() {
      $('#loginform').on('submit', function() {
        const formdata = $(this).serialize()
        $.ajax({
          url: '/users/loginjwt',
          type: 'post',
          data: formdata,
          success(res) {
            if (res.status === 200) {
              window.sessionStorage.setItem('token', res.token);
              location.href = '/user/index.html'
            }
          }
        })
        return false
      })
    })
  </script>
</body>
</html>

index.html

<script>
  if (!sessionStorage.getItem('token')) {
    location.href = '/user/login.html'
  }
</script>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="../javascripts/jquery.min.js"></script>
  <title>Document</title>
</head>

<body>
  <h1>welcome index</h1>
  <a href="javascript:;" rel="external nofollow" >退出登录</a>
  <script>
    $(function() {
      $.ajaxSetup({
        // 发送请求前触发
        beforeSend(xhr) {
          // 在此设置自定义请求头
          xhr.setRequestHeader('authorization', sessionStorage.getItem('token'))
        }
      })
      $.ajax({
        url: '/users',
        success(res) {
          console.log(res);
        }
      })
      $('a').on('click', function() {
        sessionStorage.clear();
        location.href = '/user/login.html'
      })
    })
  </script>
</body>
</html>

4.4 注意点

值得注意的是,对于 本地 token 的验证(是否存在)一定要写在页面最顶端(防止页面加载,再次发送用户列表请求)
对于 ajax请求头,一个一个加真的很烦,此处用 $ajaxSetup方法,修改ajax 的默认配置 。配置过后,写在其下边的 ajax 请求,都会带上请求头。

到此这篇关于node脚手架搭建服务器实现token验证的方法的文章就介绍到这了,更多相关node token验证 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
js全屏显示显示代码的三种方法
Nov 11 Javascript
js 3秒后跳转页面的实现代码
Mar 10 Javascript
jquery进行数组遍历如何跳出当前的each循环
Jun 05 Javascript
JS判断移动端访问设备并加载对应CSS样式
Jun 13 Javascript
zepto中使用swipe.js制作轮播图附swipeUp,swipeDown不起效果问题
Aug 27 Javascript
JavaScript必知必会(二) null 和undefined
Jun 08 Javascript
H5手机端多文件上传预览插件
Apr 21 Javascript
Node.js dgram模块实现UDP通信示例代码
Sep 26 Javascript
使用 Node.js 模拟滑动拼图验证码操作的示例代码
Nov 02 Javascript
vue 使用vue-i18n做全局中英文切换的方法
Oct 29 Javascript
Node.js EventEmmitter事件监听器用法实例分析
Jan 07 Javascript
10个最受欢迎的 JavaScript框架(推荐)
Apr 24 Javascript
Vue实现图书管理案例
Jan 20 #Vue.js
浅析JavaScript中的事件委托机制跟深浅拷贝
Jan 20 #Javascript
详解vue之自行实现派发与广播(dispatch与broadcast)
Jan 19 #Vue.js
js实现电灯开关效果
Jan 19 #Javascript
jquery实现穿梭框功能
Jan 19 #jQuery
jQuery实现穿梭框效果
Jan 19 #jQuery
element el-table表格的二次封装实现(附表格高度自适应)
Jan 19 #Javascript
You might like
PHP函数实现分页含文本分页和数字分页
2014/10/23 PHP
php设计模式之抽象工厂模式分析【星际争霸游戏案例】
2020/01/23 PHP
jquery 插件 人性化的消息显示
2008/01/21 Javascript
javascript Array.sort() 跨浏览器下需要考虑的问题
2009/12/07 Javascript
jQuery EasyUI NumberBox(数字框)的用法
2010/07/08 Javascript
Extjs中DisplayField的日期或者数字格式化扩展
2010/09/03 Javascript
jQuery插件-jRating评分插件源码分析及使用方法
2012/12/28 Javascript
html组件不可输入(只读)同时任何组件都有效
2013/04/01 Javascript
js事件冒泡实例分享(已测试)
2013/04/23 Javascript
JavaScript截取字符串的Slice、Substring、Substr函数详解和比较
2014/03/20 Javascript
jquery查找父元素、子元素(个人经验总结)
2014/04/09 Javascript
Node.js实用代码段之正确拼接Buffer
2016/03/17 Javascript
AngularJS基础 ng-focus 指令简单示例
2016/08/01 Javascript
AngularJS 指令的交互详解及实例代码
2016/09/14 Javascript
详解ECharts使用心得总结
2016/12/06 Javascript
React-Native做一个文本输入框组件的实现代码
2017/08/10 Javascript
利用express启动一个server服务的方法
2017/09/17 Javascript
JavaScript 中的 this 简单规则
2017/09/19 Javascript
详解基于vue-cli配置移动端自适应
2018/01/13 Javascript
jQuery中内容过滤器简单用法示例
2018/03/31 jQuery
React组件内事件传参实现tab切换的示例代码
2018/07/04 Javascript
vue1.0和vue2.0的watch监听事件写法详解
2018/09/11 Javascript
JS计算两个数组的交集、差集、并集、补集(多种实现方式)
2019/05/21 Javascript
[02:25]DOTA2英雄基础教程 虚空假面
2014/01/02 DOTA
[05:01]3.19DOTA2发布会 我们都是刀塔人
2014/03/25 DOTA
python+matplotlib绘制3D条形图实例代码
2018/01/17 Python
Python常见工厂函数用法示例
2018/03/21 Python
利用Python半自动化生成Nessus报告的方法
2019/03/19 Python
Python面向对象思想与应用入门教程【类与对象】
2019/04/12 Python
Python TKinter如何自动关闭主窗口
2020/02/26 Python
HashMap和Hashtable的区别
2013/05/18 面试题
《水乡歌》教学反思
2014/04/24 职场文书
国贸专业毕业求职信
2014/06/11 职场文书
党的群众路线教育实践活动查摆剖析材料
2014/10/10 职场文书
《弟子规》读后感:知廉耻、明是非、懂荣辱、辨善恶
2019/12/03 职场文书
如何用PHP实现分布算法之一致性哈希算法
2021/05/26 PHP