望着时间滴答滴答的流过,我不曾改变过 . . .

vue & nodejs jwt 的基于token身份验证

现在比较流行的验证方式,是带着token的登录验证

原理

1. 登陆时,客户端发送用户名密码
2. 服务端验证用户名密码是否正确,校验通过就会生成一个有时效的token串,发送给客户端
3. 客户端储存token,一般都会存储在localStorage或者cookie里面(vue可以存储与vuex)
4. 客户端每次请求时都带有token,可以将其放在请求头里,每次请求都携带token
5. 服务端验证token,所有需要校验身份的接口都会被校验token,若token解析后的数据包含用户身份信息,则身份验证通过,返回数据

完整例子

下面来看一个比较完整的例子,有问题可以和我交流哦,我也挺菜的:
第一步,客户端发送用户名和密码; (一般是post过去)
第二步,验证用户名密码是否正确,校验通过就会生成一个有时效的token串,发送给客户端

        if (data.toString() === req.body.pass){
            // 登陆成功,添加token验证
            let sid = req.body.pass + req.body.seccode; //密码 和 验证码组成其sid
            let jwt = new JwtUtil(sid); //将用户sid传入,生成token
            let token = jwt.generateToken();
            res.send({status:200,msg:'登陆成功',token:token});
        }else{
            res.send({status:404,msg:'口令错误'})
        }

第三步,客户端储存token,一般都会存储在localStorage或者cookie里面(这里我存储在vuex里面,进行统一管理)
第四步,客户端每次请求时都带有token,可以将其放在请求头里,每次请求都携带token

                  //使用vuex对全局token进行状态管理
                  this.$store.dispatch("set_token",res.data.token);
                  //设置:全局带token
                  this.$http.defaults.headers.common['token'] = this.$store.state.token;

store 里index.js:

import Vue from 'vue'
import Vuex from 'vuex'

//使用vuex
Vue.use(Vuex);

//一个store  , Vuex.store的 实例
const store = new Vuex.Store({
    state: {
        token : ''
    },
    getters:{            //  Getter相当于vue中的computed计算属性
        getToken: (state) => {return state.token;}
    },
    mutations: {
        set_token(state,ltoken) {   //第一个参数是拿到state对象
            localStorage.setItem('token',ltoken);
            state.token = ltoken;
        },
        del_token(state) {
            localStorage.removeItem('token');
            state.token = '';
        }
    },
    actions: {      //注册actions,类似vue里面的methods 
        //通过这个修改state里面的值
        // 可以直接用mutations修改,但是官方建议使用actions去调用mutations去修改
        set_token(context,token) {
            context.commit("set_token",token);
        },
        del_token(context){
            context.commit("del_token");
        }
    }
})

export default 

最后一步,服务端验证token,所有需要校验身份的接口都会被校验token,若token解析后的数据包含用户身份信息,则身份验证通过,返回数据
(这里,除了一些特定接口,不拦截之外,把拦截的 都需要进行验证)
(我这里是: /api/fr/articles 前台获取文章列表的接口不需要拦截; /api/imgCode 生成二维码的接口不需要拦截 /api/lone 登录发token的接口不需要拦截)
其他都需要拦截。

app.use(function (req, res, next){
    //一共三个接口不需要拦截:
    //  /imgCode   /lone /api/fr/articles
    if (req.url != '/api/fr/articles' && req.url != '/api/imgCode' && req.url != '/api/lone') {
        let token = req.headers.token;
        let jwt = new JwtUtil(token);
        let result = jwt.verifyToken();
        console.log('result是:',result);
        // 如果考验通过就next,否则就返回登陆信息不正确
        if (result == 'err') {
            console.log(result);
            res.send({status: 403, msg: '登录已过期,请重新登录',res: result});
            // res.render('login.html');
        } else {
            next();
        }
    } else {
        next();
    }
});

其中:jwt.js怎么写呢?参考于这篇文章: nodejs 基于token的身份验证

// 引入模块依赖
const fs = require('fs');
const path = require('path');
const jwt = require('jsonwebtoken');
// 创建 token 类
class Jwt {
    constructor(data) {
        this.data = data;

    }

    //生成token
    generateToken() {
        let data = this.data;
        let created = Math.floor(Date.now() / 1000);
        let cert = fs.readFileSync(path.join(__dirname, '../server/pem/rsa_private_key.pem'));//私钥 可以自己生成
        let token = jwt.sign({
            data,
            exp: created + 60 * 30,
        }, cert, {algorithm: 'RS256'});
        return token;
    }

    // 校验token
    verifyToken() {
        let token = this.data;
        let cert = fs.readFileSync(path.join(__dirname, '../server/pem/rsa_public_key.pem'));//公钥 可以自己生成
        let res;
        try {
            let result = jwt.verify(token, cert, {algorithms: ['RS256']}) || {};
            let {exp = 0} = result, current = Math.floor(Date.now() / 1000);
            if (current <= exp) {
                res = result.data || {};
            }
        } catch (e) {
            res = 'err';
        }
        return res;
    }
}

module.exports = Jwt;

公私密钥对,一般可以选择openssl进行生成.

posted @ 2019-09-28 22:46  whyaza  阅读(2317)  评论(0编辑  收藏  举报