这里要用到三个插件, 加上前端一共是至少4个插件
>>>>>>后端应用:
jsonwebtoken //生成token字符串
passport //token解析主插件
passport-jwt // 密钥解析规则插件, 有密钥解析
------------------------------------------------------------
>>>>>> 给前端使用的
jwt-decode //无密钥解析, secretOrKey 是存储在环境变量中的,因此在前端必须使用无密钥解析。
复制代码
使用jsonwebtoken进行加密 和 使用jwt无密钥解析
// jwt加密的使用:
const jwt = require('jsonwebtoken');
// 无密钥解析插件
const jwt_decode = require('jwt-decode');
//设置一个密钥
const secretOrKey = "hello world";
//待生成token的对象
const rules = { id: '0001', name: 'liyuanzhe', job: 'developer' };
// -----> 这里使用promise 方便大家分开查看这两个插件的执行
new Promise((resolve, require) => {
// jwt.sign是异步执行操作
// 使用jsonwebtoken创建字符串
// 参数 (需要加密的内容, 密钥字符串, token属性, 回调函数)
jwt.sign(rules, secretOrKey, { expiresIn: 3600 }, (err, token) => {
if (err) throw err;
token = "Bearer " + token /*根据插件作者的要求, 这里一定要写 Bearer空格*/
console.log(token);
// 打印生成的token字符串
//Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjAwMDEiLCJuYW1lIjoibGl5dWFuemhlI iwiam9iIjoiZGV2ZWxvcGVyIiwiaWF0IjoxNTU3Mzk3ODYwLCJleHAiOjE1NTc0MDE0NjB9.fT4eKuvAbvH66QM frSHEm1UmeHPedYOWYIr3rNwAPg8
// res.send(token) 实际开发发送给前端
resolve(token);
});
}).then((token) => {
//shiyong jwt-decode 对token 进行无密钥解析
console.log(jwt_decode(token));
//输出结果:
// { id: '0001', name: 'liyuanzhe', job: 'developer',
// iat: 1557397860, exp: 1557401460 }
// iat : 生效时间
// exp :过期时间
//前端拿到这个字符串后应当进行解析, 然后进行localstorage,sessionStorage存储,
//发送网络请求时,再把token字符串再发给后端,
})
复制代码
后端对发送给前端的token进行有密钥解析
passport //token解析主插件 相当于各种passport策略的容器
passport-jwt // 密钥解析规则(策略)插件, 有密钥解析
接下来以这个为例:
// /*
// passport有策略(strategy)的概念. strategy是少量预约义的方法,
// 它们会在请求抵达真正的路由之前执行.假如你定义的strategy认定某个请求非法,
// 则该路由不会被执行, 而是返回401 Unauthorized.
// */
const express = require('express');
const server = express();
//使用body解析中间件
const bodyParser = require('body-parser');
server.use(bodyParser.urlencoded({ extended: false }));
server.use(bodyParser.json());
server.listen(8080);
const router = express.Router(); //引入路由 ,之后发起网络请求做判断
//引入passport插件
const passport = require('passport');
//对passpor进行初始化
server.use(passport.initialize());
// jwt策略函数
const JwtStrategy = require('passport-jwt').Strategy;
// 抽取jwt函数
const ExtractJwt = require('passport-jwt').ExtractJwt;
//设置策略选项 1. 密钥 2.抽取token的方法
let opts = {
// 存入环境变量的混淆密钥
secretOrKey: "hello world",
// 定义从请求头的Authrization抽取token数据
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
}
// 构造 策略对象
var jwtConfig = new JwtStrategy(opts, (jwt_payload, next) => {
// jwt_payload 解析好的 token字符串,
// 和 jwt-decode 解析的一样, 但是这个会进行密钥的判断
// 如果密钥匹配失败, 直接结束返回401状态码
console.log(jwt_payload)
//这个在实战开发中会有和数据库中id查找
// DB_User.findById(jwt_payload.id){
// .then(user => {
// return done(null, user)
// }).catch(err => {
// console.log(err)
// })
// }
//为了测试我们就无脑下一步了
next(null, jwt_payload)
});
// 应用在passport中
passport.use(jwtConfig);
// passport.authenticate("加密算法策略", 验证条件,回调)
router.get('/testJWT', passport.authenticate("jwt", { session: false }), (req, res) => {
res.json({ ok: 1 })
})
server.use('/test', router);
复制代码
测试:
数据:
{ id: '0001', name: 'liyuanzhe', job: 'developer'}
前端生成token :
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjAwMDEiLCJuYW1lIjoibGl5dWFuemhlIiwiam9iIjoiZGV2ZWxvcGVyIiwiaWF0IjoxNTU3NDA0NzE1LCJleHAiOjE1NTc0MDgzMTV9.jqwwdAH4qKFCX7t0xHJ0YXiprNmlSpM0sDc8PwoWSbc
使用jwt-decode 解析token:
{ id: '0001', name: 'liyuanzhe', job: 'developer', iat: 1557404715, exp: 1557408315 }
使用postman测试
输入有效的token:
输入过期的token:总结:
server passport passport-jwt 三者之间的关系
三层嵌套use
// 创建解析规则部分
server.use (
passport.use(
new passport-jwt.Strategy(
//策略选项
{secretOrKey: "hello world",jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()},
//回调函数
(jwt_payload, next)=>{
next(null, jwt_payload)
}
)
)
)
// ------> 使用部分
// passport.authenticate("jwt", 验证条件,回调)
router.get('/testJWT', passport.authenticate("jwt", { session: false }), (req, res) => {
res.json({ ok: 1 })
})
server.use('/test', router);
复制代码