解析jsonwebtoken(jwt)在nodejs中的使用。

6,858 阅读3分钟

这里要用到三个插件, 加上前端一共是至少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);