一、jwt
NodeJS 基于 JWT 实现身份验证(token、自动登陆)
jwt简介:
jwt
全称json web token
。
jwt.io是用于令牌签名/验证的库,用来生成jwt。
简单理解一下,就是 jwt.io这个库,提供了一种方法可以将一些信息加密,形成一串长长的字符串,类似于eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
这个长长的字符串我们称之为令牌(jwt),其用于客户端与服务器端两端之间的身份验证。
举个例子,用户在登录一个系统时,如果登录成功,服务器端会将用户信息(例如用户id)加密形成一个长长的字符串,即jwt,发送回客户端。
客户端将jwt进行妥善保管。之后进行所有跟用户身份有关的操作,客户端都需要提供jwt(我们一般把jwt放入请求头),供服务器端验证身份,服务器端拿到jwt进行解密就能获得加密前的数据,就能判断用户身份是否正确。
安装
npm install jsonwebtoken
二、测试工具chai/mocha:
安装moncha,安装断言库 chai
npm install chai -S
npm install mocha -S
一个测试文件的内容主要写法有三部分:
describe(groupName, callback):测试分组,describe可以多层嵌套使用
it(‘testItemName’, callback):测试项
注意:
- 测试同步函数时,callback内无需传入参数
- 测试异步函数时,callback内需要传入一个参数,通常命名为done
断言:对测试内容的判断,断言是否满足
默认使用的是Node.js的assert模块 , 也可以自己选择其他的断言库:
断言库列表:
- should.js:should语法风格(BDD风格)的断言库
- expect.js:expect语法风格(简约BDD风格)的断言库
- chai:可自由在(assert()、should()、expect())三种风格进行选择的断言库
- better-assert:~
- unexpected: ~
第三方断言库的使用方法:
- 方式1:在每个测试文件中都使用require引入断言库依赖,然后即可在当前的测试文件中使用了
- 方式2:在test/目录下添加一个mocha.opts配置文件,在里面写入要使用的断言库,之后即可在所有的测试文件中直接使用了
三、demo:
JWT工具 :
JWT.js :
// 安装:
// npm install jsonwebtoken
const jwt = require('jsonwebtoken');
const secret = 'test_key';//
const JWT = {
//encrypt加密函数
// jsonwebtoken提供了一个函数sign用于加密生成jwt,
// 格式jwt.sign(payload,secretOrPrivateKey,options)
// 参数 payload
// 表示要加密的数据
// 参数 secretOrPrivateKey
// 自定义字符串,这个字符串在解密时需要用到,
// 在这里我随便写了一个‘token’。这相当于一个密钥secret,服务器端需要妥善保管。
// 参数 options
// 其他内容,可以设置令牌有效时间{expiresIn:time}。
// time的取值,'15d'表示15天,'2h'表示2小时,……
encrypt: function (payload, time) { //data加密数据,time过期时间
try {
return jwt.sign(payload, secret, {expiresIn: time})
} catch (e) {
return '';
}
},
//
//decrypt解密函数
// jsonwebtoken提供了一个函数verify用于解密jwt,
// 格式jwt.verify(jwtString,secretOrPublicKey)
// 参数 jwtString
// 表示需要解密的令牌
// 参数 secretOrPublicKey
// 表示加密时用到的自定义字符串,即密钥
decrypt: function (token) {
try {
return jwt.verify(token, secret); // 如果过期将返回false
} catch (e) {
return false;
}
}
}
module.exports = {JWT};
测试
const {JWT} = require("./JWT");
var {expect} = require("chai");
var assert = require('assert');
describe("Arithmetic", function () {
it("Addition", function () {
expect(1 + 1).to.equal(2);
})
it("Subtraction", function () {
expect(1 - 1).to.equal(2);
})
})
describe("JWT Test", function () {
it("test1", function (done) {//不要使用箭头函数
const payload = {
name: 'xq',
age: 18,
};
//加密,10秒过期
let token = JWT.encrypt(payload, '10s');
console.log("token === ", token);
//token ===
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
// eyJuYW1lIjoieHEiLCJhZ2UiOjE4LCJpYXQiOjE2MDU3NzMwMjQsImV4cCI6MTYwNTc3MzAzNH0.
// NASClBh_Yz2YhhTR8AkXEmh3DuexSYqu-Z04qSAe2GU
//解密
const info = JWT.decrypt(token);
console.log("info === ", info);
// { name: 'xq', age: 18, iat: 1605772504, exp: 1605772514 }
// iat: 指定token发布时间
// exp: 指定token过期时间
// 时间转换工具 : https://tool.lu/timestamp/
setTimeout(function () {
const info2 = JWT.decrypt(token);
console.log("info2 === ", info2);
console.log('3==============', new Date().getTime() / 1000)
done();//延时必备【2/2】
}, 10 * 1000)//设置9秒时不过期,10秒才过期
console.log('1==============', new Date().getTime() / 1000)
this.timeout(15 * 1000);//延时必备【1/2】,可放在setTimeout前面或者后面都可以,//指定程序运行时长
console.log('2==============', new Date().getTime() / 1000)
})
}
)