Mysql在Node中的具体使用

2,372 阅读18分钟

一、win10使用mysql shell命令操作mysql数据库

mysql的安装文件:

链接:https://pan.baidu.com/s/1G2RsqXKcRzCbRFc2xfCCng 
提取码:9m0m

mysql有自己的客户端连接工具了。下面就介绍如如何使用mysql shell.

安装mySql 的时候需要安装 mysql shell, 如果没有选,需要后面另行安装

  1. 打开mysql shell

打开cmd。win徽标键+R,输入cmd。

  1. 在cmd中输入mysqlsh,进入MySQL shell命令行。

  1. 输入\connect root@127.0.0.1 连接mysql。 root是用户名,@后面接数据库ip地址。回车后输入密码

  1. 连接成功后输入"\sql" 进入sql命令模式;

在输入show datebases; 就会显示数据库列表了。 使用use XXX来选择某一个数据库。之后就能正常使用所有mysql 语法了。

比如:

通用命令

命令 别名/快捷方式 描述
\help \h or ? 打印有关MySQL Shell的帮助,或搜索联机帮助。
\quit \q or \exit 退出MySQL Shell。
\ 在SQL模式下,开始多行模式。输入空行时缓存并执行代码。
\status \s 显示当前的MySQL Shell状态。
\js 将执行模式切换为JavaScript。
\py 将执行模式切换为Python。
\sql 将执行模式切换为SQL。
\connect \c 连接到MySQL服务器。
\reconnect 重新连接到同一个MySQL服务器。
\use \u 指定要使用的架构。
\source \. 使用活动语言执行脚本文件。
\warnings \W 显示语句生成的任何警告。
\nowarnings \w 不要显示语句生成的任何警告。
\history 查看和编辑命令行历史记录。
\rehash 手动更新自动完成名称缓存。
\option 查询和更改MySQL Shell配置选项。
\show 使用提供的选项和参数运行指定的报告。
\watch 使用提供的选项和参数运行指定的报告,并定期刷新结果。

mysqlsh里面常用的命令:

  • 链接数据库: connect root:mysql@127.0.0.1

  • 切换到sql模式 sql

  • 显示数据库端口: select @@port

二、 MySql Command Line Client使用

备注:我安装数据库设置的默认端口3306 ,密码是123456 ,根用户root

2.1 启动与退出

1、进入MySQL:启动MySQL Command Line Client(MySQL的DOS界面),直接输入安装时的密码即可。此时的提示符是:mysql>

2、退出MySQL:quit或exit

2.2 数据库操作

1、创建数据库

命令:create database <数据库名>;

例如:建立一个名为jd的数据库
mysql> create database jd;

2、显示所有的数据库

命令:show databases; (注意:最后有个s)

mysql> show databases;

3、删除数据库

命令:drop database <数据库名>

例如:删除名为 jd的数据库
mysql> drop database jd;

4、连接数据库

命令:use <数据库名>

例如:如果jd数据库存在,尝试存取它:
mysql> use jd;
屏幕提示:Database changed

5、查看当前使用的数据库

mysql> select database();

6、当前数据库包含的表信息:

mysql> show tables; (注意:最后有个s)

2.3 表操作,操作之前应连接某个数据库

1、建表

命令:create table <表名> ( <字段名> <类型> [,..<字段名n> <类型n>]);

mysql> create table MyClass(
 id int(4) not null primary key auto_increment,
 name char(20) not null,
 sex int(4) not null,
 degree double(16,2));

2、获取表结构

命令:desc 表名,或者show columns from 表名

下面3个命令都可以获取表结构

mysql>DESCRIBE MyClass;
mysql> desc MyClass;
mysql> show columns from MyClass;

3、删除表

命令:drop table <表名>

例如:删除表名为 MyClass 的表
mysql> drop table MyClass;

4、插入数据

命令:insert into <表名> [( <字段名>[,..<字段名n > ])] values ( 值 )[, ( 值n )]

例如,往表 MyClass中插入二条记录, 这二条记录表示:编号为的名为Tom的成绩为96, 编号为 的名为Joan 的成绩为82
mysql> insert into MyClass values(1,'Tom',1,96),(2,'Joan',1,82);

5、查询表中的数据

1)、查询所有行

命令:select <字段,字段,...> from < 表名 > where < 表达式 >

例如:查看表 MyClass 中所有数据
mysql> select * from MyClass;

2)、查询前几行数据

例如:查看表 MyClass 中前行数据

mysql> select * from MyClass order by id limit 0,2;
或者:
mysql> select * from MyClass limit 0,2;

6、删除表中数据

命令:delete from 表名 where 表达式

例如:删除表 MyClass中编号为 的记录
mysql> delete from MyClass where id=1;

7、修改表中数据

update 表名 set 字段=新值,…where 条件

mysql> update MyClass set name='Mary' where id=1;

7、在表中增加字段:

命令:alter table 表名 add字段 类型 其他;

例如:在表MyClass中添加了一个字段passtest,类型为int(4),默认值为
mysql> alter table MyClass add passtest int(4) default 2;

8、更改表名

命令:rename table 原表名 to 新表名;

例如:在表MyClass名字更改为YouClass
mysql> rename table MyClass to YouClass;

9、更新字段内容

update 表名 set 字段名 = 新内容
update 表名 set 字段名 = replace(字段名,’旧内容’,'新内容’)

10、使用数据库

use jd;
source D:\vip\vue-jd\jd.sql

三、通过express-generator生成一个express的框架

3.1 项目生成并启动

安装:
yarn add express-generator

项目生成:ejs为末班引擎, less作为css预处理
npx express --view=ejs  --css=less myapp

运行项目:
cd myapp
npm install
nodemon bin/www  //启动并实时监听

注:如果没有全局安装nodemon , 通过npm start启动 或者 node bin/www 启动

3.2 添加中间件,方便获取接口请求参数

定义:

var url  = require('url');
...
...
//注意post请求的时候可以通过req.body获取参数,但是url不行 通过url去解析
// 写成中间件形式
function getParamsMiddle(req, res,next) {
  if(req.method.toLocaleLowerCase()=='post') {
      query = req.body;
  } else {
      const urlJson = url.parse(req.url,true);
      query = urlJson.query;
  }
  req.query = query;
  console.log('参数');
  next();
}

使用:

四、文件系统数据库fs

node.js中实现持久化的多种方法

  • 文件系统 fs
  • 数据库
    • 关系型数据库-mysql
    • 文档型数据库-mongodb
    • 键值对数据库-redis

4.1 在routes新建 fs.js

var express = require('express');
var fs = require('fs');
var path = require('path');
var router = express.Router();

const {promisify} = require('util');
var base = path.join(__dirname,'../data/db.json');
var readFile = promisify(fs.readFile);
var writeFile = promisify(fs.writeFile);

// 文件读取
router.get('read',function(req, res, next){
    readFile(base).then((data)=>{
        console.log(data.toString())
        res.json(data);
    });

})
/* 文件写入 */
router.get('/write', function(req, res, next) {
   var params = req.query;
  
   readFile(base).then((data)=>{
    console.log(data.toString());

    var o1= JSON.parse(data.toString())
    var dataTo = {...o1,...params};
     
    return writeFile(base,JSON.stringify(dataTo));
    
}).then((data)=>{
    // res.json(data)
    res.send('write success');
});

});
  
  module.exports = router;

4.2 在配置文件app.js文件引入路由

var fsFile = require('./routes/fs');
..
..
..
app.use('/fs', fsFile);

4.3 读取文件并写入文件

前面在 4.1.1 已经做好配置, 直接访问

http://localhost:3000/fs/read 可以读取data文件夹db.json的数据
http://localhost:3000/fs/write?city=hubei  可以通过参数以为key,value的形式写入到db.json文件中

五、 MySQL安装、配置

六、 node.js驱动mysql数据库

6.1 安装mysql2

node mysql2模块是node mysql模块的一个扩展

yarn add mysql2 
或者
npm install mysql2

如果使用mysql的时候, 可能会提示让你升级

const mysql = require('mysql');
console.log(mysql)

使用mysql2;链接数据库 ,并打印出mysql的方法:

const mysql = require('mysql2');
console.log(mysql)

6.2 mysql 链接数据库

mysql 链接数据库 可以通过createConnection 也可以通过createPool

比较:

  • createConnection方法创建连接对象 单个连接阻塞。在执行一个查询时,它不能执行其他查询。因此,数据库吞吐量可能会降低。

  • createPool 方法创建连接池

池管理许多延迟创建的连接。当一个连接忙于运行查询时,其他连接可用于执行后续查询。这会导致应用程序性能的提高,因为它允许多个查询并行运行。

6.2.1 createConnection 建立连接&关闭连接(方式一)

(1)createConnection方法创建连接对象 使用createConnection方法创建一个表示与mysql数据库服务器之间连接的connection对象

const mysql = require("mysql");
var connection = mysql.createConnection(options); 

options:
{
  host:'127.0.0.1',  //主机ip
  user: 'root',  //数据库 用户名
  password: '123456',  // 修改为你的密码
  port: '3306',  //数据库端口号
  database: 'jd'  // 请确保数据库存在
}

(2)用对象的connect方法建立连接。

connection.connect(function(err) { console.log('数据库连接成功!') }); 

(3)关闭连接:connection对象的end方法和destory方法。

connection.end(function(err) { console.log('数据库已经关闭!') }); 
connection.destroy();

(4) 完整示例

01-mysql.js

// 引入
const mysql = require('mysql2');
// 创建数据库连接
var connection = mysql.createConnection({
    host: 'localhost',
    port: 3306,
    user: 'root',
    password: '123456',
    database: 'test'
});

// 连接
connection.connect(function (err) {
    if (err) {
        console.log('[query] - :' + err);
        return;
    }
    console.log('数据库连接成功!') 
});

// 查询数据
connection.query('select * from MyClass', function (error, results, fields) {
    if (error) throw error;
     console.log(results);
     console.log(fields);
});

//关闭连接
connection.end(function (err) {
    if (err) {
        return;
    }
    console.log('数据库已经关闭!')
});

练习中间数据库表的而一些操作:


// 新增数据表
/* create table websites(
    id init(4) not null primary key auto_increment,
    name char(20) not null,
    url char(20) not null,
    country char(50) not null,     
) */

// ******插入一条数据到websites表 *******
var addSql = 'INSERT INTO websites(name,url,country) VALUES(?,?,?)';
var addSqlParams = ['菜鸟', 'https://test.com',  'CN'];
//执行
conn.query(addSql, addSqlParams, function (err, res) { 
  if (err) {
    console.log('[INSERT ERROR] - ', err.message);
    return;
  }
  console.log("数据库增的结果:");
  console.log(res);
});
// ******end *******

// ******从websites表删除一条数据 *******
var delSql = 'DELETE FROM websites where id=1'; 
conn.query(delSql, function (err, res) { 
  if (err) {
    console.log('[DELETE ERROR] - ', err.message);
    return;
  }
  console.log("数据库删的结果:");
  console.log(res);
});

// ************ end ****************


// // ******修改websites表中一条数据 *******
var modSql = 'UPDATE websites SET  url = ? WHERE id = ?';
var modSqlParams = ['https://bang.com', 3];
//修改
conn.query(modSql, modSqlParams, function (err, res) {
  if (err) {
    console.log('[UPDATE ERROR] - ', err.message);
    return;
  }
  console.log("数据库修改的结果:");
  console.log(res);
});
// ************ end ****************

// ******查找websites表中的数据 *******
var sql = 'SELECT * FROM websites';
conn.query(sql, function (err, res) {
  if (err) { 
    console.log('[SELECT ERROR] - ', err.message);
    return;
  }
  console.log("数据库查的结果:");
  console.log(res); 
});

// ************ end ****************

mysql执行sql语句 有2种方式

  • conn.query
  • conn.execute
    conn.execute 是mysql2新增

把上面01-mysql.js换一种写法,利用 mysql2的新特性

const mysql = require('mysql2/promise');
    // mysql2 是mysql的一个扩展
    console.log(mysql);
(async ()=>{
//    // 连接配置
    var options= {
        host:'127.0.0.1',
        user: 'root',
        password: '123456',  // 修改为你的密码
        port: '3306',
        database: 'jd'  // 请确保数据库存在
    }

   var conn = await mysql.createConnection(options);
    // mysql执行sql语句
    // 1. conn.query  
    // 2. conn.execute  mysql2新增

   var co01 = await conn.execute('select * from myclass');
    console.log(co01[0])


    // ******插入一条数据到websites表 *******
    var addSql = 'INSERT INTO websites(name,url,country) VALUES(?,?,?)';
    var addSqlParams = ['阮某', 'https://ruan.com',  'CN'];
    //执行
    var co02= await conn.execute(addSql, addSqlParams);
    console.log('新增一条数据:'+co02[0].affectedRows);

    // ******end *******

})();


6.2.2 createPool 创建连接池(方式二)

连接池有助于减少连接到MySQL服务器的时间,通过重用以前的连接 可以避免查询的延迟,减少建立新连接所带来的开销。

在服务器应用程序中,如果为每一个接收到的客户端请求都建立一个或多个数据库连接,将严重降低应用程序性能。

因此在服务器应用程序中通常需要为多个数据库连接创建并维护一个连接池,当连接不再需要时,这些连接可以缓存在连接池中,当接收到下一个客户端请求时,从连接池中取出连接并重新利用,而不需要再重新建立连接。

(1)创建连接池 createPool方法

var pool = mysql.createPool(optioins);

options参数包含createConnection方法中可以使用的各种属性,除此之外还有以下属性:createConnection,waitForConnections,connectionLimit,getConnection。

var pool = mysql.createPool({
    host:'127.0.0.1',
    user: 'root',
    password: '123456',  
    port: '3306',
    database: 'jd'  ,
    charset:'utf8', //应该设置编码(省略在某些情况下会有错误)
    
     //以下选项均为默认值(如果不需要变动可省略)
    acquireTimeout:10000, //获取连接的毫秒
    waitForConnections: true, //为true时,连接排队等待可用连接。为false将立即抛出错误
    connectionLimit: 10, //单次可创建最大连接数
    queueLimit: 0 //连接池的最大请求数,从getConnection方法前依次排队。设置为0将没有限制
});

(2)从连接池中取出连接

连接池并未初始连接所有连接,当需要操作数据库时需要先进行获取连接对象 获取连接对象的方法(pool.query() || pool.execute() || pool.getConnection()) 注:query()和execute()作用一样(自动获取连接释放连接)

  • 方式一.query 连接
// true 表示条件,单个可直接使用如下,多个使用数组格式。例:['name',5]
 pool.query("select * from websites ",true,(err,res)=>{
        console.log(res)
})
  • 方式二. getConnection 连接 pool.getConnection() 可以获取到连接对象 操作后建议主动的释放连接
    pool.getConnection(function(err, conn) {
    conn.query(/* ... */);
    // 完成后请不要忘记释放连接!(将连接返回到连接池中)
    conn.release();
    })

回调函数中的err为错误对象,connection为获取到的连接对象。 可以获取到连接对象 操作后建议主动的释放连接

(3)当连接不再使用时,用connection对象的release方法将其归还到连接池中。

connection.release();

release方法将其归还到连接池中 (4)当一个连接不再需要使用且需要从连接池中移除时,用connection对象的destroy方法。

connection.destroy(); 

连接移除后,连接池中的连接数减一

(5)当一个连接池不再需要使用时,用连接池对象的end方法关闭连接池。

pool.end();

(6)完整示例

const mysql = require('mysql2');
var pool = mysql.createPool({
    host: 'localhost',
    port: 3306,
    user: 'root',
    password: '123456',
    database: 'test'
});
pool.getConnection(function(err, connection) {
    if(err){
        console.log("建立连接失败");
    } else {
        console.log("建立连接成功");
        connection.query('select * from websites', function(err, rows) {
            if(err) {
                console.log("查询失败");
            } else {
                console.log(rows);
            }
        })
    }
    pool.end();
})

(7) 分块查询

  • 通过conn.pause()可暂停查询,当大量数据处理时很有用
  • 通过conn.resume()可继续查询,当处理完一段之后可通过该方法继续IO操作
pool.getConnection((err,conn)=>{
  let query = conn.query('select * from websites');
  query.on('error',err=>{
      // 错误处理,在这个事件之后会发送一个'end'事件
  })
  .on('fields',(fields)=>{
      // 查询行字段信息
      console.log('fields');
      console.log(fields);
  })
  .on('result',row=>{
      // 暂停(row为查询的数据每查询到一行触发一次)
      console.log('row');
      console.log(row);
      conn.pause();
      // 继续查询
      conn.resume();
  })
  .on('end',_=>{
      conn.release();
      // 无论成功与否最后均会触发该事件
  })
  
})

七、mysql中的事务(TRANSACTION)

使用场景是执行一个sql组,包含多个sql语句。想了想,这些sql语句要么同时执行,要么同时不执行,才能够保证数据的完整性。所以简单的在sql语句正式执行的最前面加上begin(或 start transaction),在sql语句结尾加上commit。

7.1 什么是事务?

事务(TRANSACTION),就是mysql的一个具有完整逻辑的sql组,这个组里包含多个sql操作。这些sql必须同时执行,这个逻辑才算完成。要么,就回滚(rollback)到事务执行之前的数据。 最开始学习事务的时候,老师习惯讲到银行转账的情景。即a用户给b用户转账,需经过a用户扣款,b用户到账。如果在a用户扣款之后,环节发生了错误,需要a用户扣款取消,否则数据会出现a用户扣款,b用户未到账,金额的总数出现了错误。此时就需要在转账这个操作中加入事务,要么同时执行(a扣款,b到账)成功,否则回滚(a扣款,异常错误,b账号未到账,取消a扣款)。这也是事务中特性的完整性、一致性的概念。

重要:mysql的myisam类型引擎不支持事务。

7.2 事务的特性

原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

7.3 事务的执行过程

1、begin(或start transaction),开始事务。 2、执行insert、update、delete的sql语句。 3、如果sql语句执行失败,可手动rollback。回滚事务。否则执行commit提交事务。

begin;   //开始事务
update account set money=money+500 where user_id=2;
update account set money=money-500  where user_id=3;
rollback; //回滚事务,回滚后,不执行后续语句,包括commitcommit; //提交事务

7.4 事务的自动提交

mysql的autocommit代表事务是否自动提交。mysql默认为自动提交,即当begin开始一个事务后,关闭mysql会话窗口,没有执行rollback或者commit操作,sql语句会自动提交。当autocommit关闭后(autocommit=0),需要执行commit才会将事务提交,关闭mysql会话后,则不会提交事务。

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.04 sec)


以上命令来查看当前会话状态,value列的on表示当前为自动提交状态。 关闭自动提交可以执行set autocommit=0;

#0 为关闭,1为开启
mysql> set autocommit=0;

7.5 事务操作示例

/**
 * 1、使用```pool.getConnection()```获取到连接对象```conn```
 * 2、使用```conn.beginTransaction()```声明开始事务操作
 * 3、使用```conn.rollback()```进行事务回滚
 * 4、使用```conn.commit()```进行事务提交
 */
pool.getConnection(function(err, conn) {

    conn.release(); //试验证明 该方法放在此处调用也是可行的
    conn.beginTransaction(err=>{
        conn.query('update websites set url=? where id=?',['123',5],(err,res)=>{
            if(err){
                // 使用return是防止代码往下运行
                return conn.rollback(_=>{
                    // 回滚后 会执行该回调函数(此处可处理一些后续的额外操作)
                });
            }
            conn.query('update websites set url=? where id=?',['456',6],(err2,res2)=>{
                if(err2){
                    console.log('err')
                    return conn.rollback();
                } else {
                    console.log(res2);
                }
               
                // 执行完所有操作后 进行提交
                conn.commit(err3=> {
                    if(err3) {
                        return conn.rollback();
                    }
                    console.log('success!');
                });
            })
        })
    })
     
});

八、 mysql 连接通过ORM框架 sequelize

8.1 什么是 ORM?

它是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的「虚拟对象数据库」。

用来把对象模型表示的对象,映射到基于 SQL 的关系模型数据库结构中去。

ORM 技术是在对象和数据库之间提供了一条桥梁,前台的对象型数据和数据库中的关系型的数据通过这个桥梁来相互转化。

8.2 安装 sequelize并引入

yarn add sequelize

8.3 创建连接对象,并模块化:

dbConn.js

const Sequelize = require('sequelize');

// 数据库配置文件
var config = {
    host: "localhost",
    user: "root",
    password: "123456",
    database: "jd"
};

var sequelize = new Sequelize(config.database, config.user, config.password, {
    host: config.host,
    dialect: 'mysql',
    pool: {
        max: 5,
        min: 0,
        idle: 30000
    }
});

我们根据数据库的一些参数,创建了sequelize数据库连接模块,并对外引用。

8.4 定义数据表结构,将表结构写进代码里:

建议每个表对应一个文档,放入项目的单独目录下,例如我通常放进了models下,这里拿我创建的一个todolist表来做示例,在models目录中创建todolist.js文件,代码如下:

定义模型fruit,建表

var Sequelize = require('sequelize');
var seq = require('./dbConn.js');

  // 定义模型,建表
  const Fruit = seq.define("fruit", {
    name: {
        type: Sequelize.STRING(20),
        allowNull: false
    },
    price: {
        type: Sequelize.FLOAT,
        allowNull: false
    }
},
    {
        timestamps: false
    });

    module.exports = Fruit;

用sequelize.define()定义Model时,传入名称fruit,默认的表名就是fruits。第二个参数指定列名和数据类型,如果是主键,需要更详细地指定。第三个参数是额外的配置,我们传入{ timestamps: false }是为了关闭Sequelize的自动添加timestamp的功能。所有的ORM框架都有一种很不好的风气,总是自作聪明地加上所谓“自动化”的功能,但是会让人感到完全摸不着头脑。

8.5 同步数据表结构

在/models目录下,新建syncTable.js,代码如下

var todolist = require('./todolist.js');

// 同步表结构
todolist.sync({
    force: true  // 强制同步,先删除表,然后新建
});

当我们换台电脑继续项目的时候,不用手动去同步数据表结构了,只需要执行一下该文件就可以了。

node models/syncTable.js

8.6 创建一些初始数据

以表fruit为例演示:

   
   var Fruit = require('./models/fruit.js');
   (async () => { 

    
        // 给数据表添加数据
        ret = await Fruit.create({
            name: "猕猴桃",
            price: 13.5
        })

        ret = await Fruit.create({
            name: "桃子",
            price: 5
        })

            // 查询数据表里的数据
        ret2 = await Fruit.findAll()
        console.log(ret2);


        // 使用实例方法
        Fruit.findAll().then(fruits => {
        const [f1] = fruits;

        fruits.forEach((option,index)=>{
            console.log(option);
        })
        console.log(`买5kg${f1.name}需要¥${f1.totalPrice(5)}`);      
        });

        //找出某一个水果
        Fruit.findOne({ where: { id: 3 } }).then(fruit => {
        // fruit是首个匹配项,若没有则为null
        console.log(fruit.get());
        });

   })()
   

九、jwt-simple 包使用详解

编码解码模块

9.1 安装

yarn add jwt-simple

9.2 生成token & 解析token

const tokenExpiresTime = 1000 * 60 * 60 * 24 * 7

//秘钥
const jstSecret = 'jstSecret'

//需要加密的对象
const payload = {
    user:'wang',
    environment:'web',
    expires: Date.now() + tokenExpiresTime
}

//encode 生成token
var token = jwt.encode(payload, jstSecret)
console.log('token: ', token)

//decoded  解析token
var decoded = jwt.decode(token, jstSecret)
console.log('decoded: ', decoded)

执行结果:

token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoid2FuZyIsImVudmlyb25tZW50Ijoid2ViIiwiZXhwaXJlcyI6MTUzNTUyMDk1MTcxOX0.4rmP6UeeJ3mQbHfplruH15PvuUxPzFTxAfVnPgA7sgo decoded: { user: 'wang', environment: 'web', expires: 1535520951719 }

9.3 token

整个token 分为三部分:

  • 头部(header)
  • 载荷(payload, )
  • 签证(signature)

上方截图中的token字符串是由此三部分经过base64加密得到的

9.3.1 Header

{
  'typ': 'JWT',
  'alg': 'HS256'
}

algorithm 默认的为HS256,源码中可以看到其他可选

/**
 * support algorithm mapping
 */
var algorithmMap = {
  HS256: 'sha256',
  HS384: 'sha384',
  HS512: 'sha512',
  RS256: 'RSA-SHA256'
};

9.3.2 Payload

token 的核心,一般主要包括:
iss(Issuer): token 签发者
sub(Subject): jwt所面向的用户
aud(Audience): token 收件人
exp(Expiration Time): token 的过期时间,一般当前时间加期限
nbf(Not Before): 验证该时间之前token 无效
iat(Issued At): token 签发时间
jti(JWT ID): jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击

9.3.3 signature

签名创建,使用编码后的header 和payload,通过指定的算法加秘钥得到的,秘钥必须保存在服务器端。例如:

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

9.4 jwt 编码解码方法

jwt_encode(payload, key, algorithm, options)
jwt_decode(token, key, noVerify, algorithm)

9.5 使用说明

服务器对用户提交的信息(一般用户名密码)验证成功后,服务器根据提交的公共信息(用户名或ID,不能使用敏感信息如密码,因为token在客户端也是可以被解密的)外加服务器持有的秘钥生成token并返回给客户端,客户端在随后需要验证的请求中携带该token,服务器每次处理请求之前先通过该token验证用户的合法性(签发者是不是服务器自己,token是否过期,是否在有效期内),通过后再交由其它模块处理请求。

一般token获取验证模块作为中间件

参考: www.jianshu.com/p/c148a3e9e…