• vue项目中实现用户登录以及token验证


    前言

    用户登录这个功能在现在越来越普遍,我也就研究了一下,本文主要讲登录这个功能中token的验证功能,本例使用的是vue框架,如何实现用户登录功能的token验证,以及整个的逻辑关系,也会将涉及到的其他知识点都讲清楚,让大家更容易更透彻的了解这个功能。废话不多说,看正文!


    一、总体逻辑图

    总体就是这样,接下来细说每个部分涉及的知识点和代码。 在这里插入图片描述

    二、各环节涉及知识点以及代码

    1.jwt(这里只说用法,至于为什么用它,详细可查官网)

    用于生成token和token的解析验证 1.JWT的组成: 一个JWT实际上就是一个字符串,它由三部分组成:头部(Header)载荷(Payload)签名(signature).

    • JWT的组成:

    一个JWT实际上就是一个字符串,它由三部分组成:头部(Header)载荷(Payload)签名(signature).

    • token生成:
    //content:需要传递的主题信息,如:用户id
    //secretOrPrivateKey:加密的key
    jwt.sign({
          var token = jwt.sign(content, secretOrPrivateKey, {
    expiresIn: 10 // 多久过期,以s作为单位
    }); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • token解析验证
    jwt.verify(token, secretOrPrivateKey, function (err, decode) {
    if (err) { // 当token过期,或这是一个伪造的token,或这是无效的token时会触发此逻辑
    console.log(err)
    } else {
    console.log(decode.msg);//得到token中传递的token主题信息,如:用户id
    }
    }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    实际项目后端接口项目代码如下:

    //app.js  ,后端验证解析token接口,前端访问这个接口完整url为baseurl+'/validate'
    const jwt = require('jsonwebtoken');
    //创建服务器
    let app=express();
    //创建端口
    app.listen(3000);
    app.use(cors({
    
        origin:['http://127.0.0.1:8080','http://localhost:8080']
      
      }));
    //挂载用户路由  前缀为/user
    app.use('/user',userRouter);
    //验证token的接口
    let secret="mouchun.com";
    app.get('/validate',(req,res)=>{
      let token = req.headers['user-token'];  //我们会把token放到我们自己设置的http的头authorization中,在这里可以直接拿到
      console.log(token);
      jwt.verify(token,secret,(err,decode)=>{     //验证token
          if(err){
              return res.json({
                  code:1,
                  data:'token失效了'
              })
          }else{
              // token合法  在这里,需要把token的时效延长,
              res.json({
                  code:0,
                  username:decode.username,
                  token:jwt.sign({username:'Fan'},secret,{ //合法时,我们需要重新生成一个token,我们每次切换路由,都要重新生成一个token
                      expiresIn:20
                  })
              })
          }
      })
    }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    //user.js,后端登录接口,前端访问这个接口完整url为baseurl+'/user/v1/login'
    const jwt = require('jsonwebtoken');
    const router=express.Router();
    //添加用户登录路由
    router.post('/v1/login',(req,res)=>{
        console.log(req.body);
        var $uname=req.body.uname;
        var $upwd=req.body.upwd;
        console.log($uname,$upwd);
        var sql='select*from lc_user where uname=? and upwd=?';
        pool.query(sql,[$uname,$upwd],(err,result)=>{
            if(err) throw err;
            if(result.length>0){
                 // 把userId和其它相关信息加密成一个token,返回给前端
                let userInfo = {
                    userId: result[0].uid,
                }
            // 生成token
            let token = jwt.sign(userInfo, "mouchun.com", {
                // expiresIn: "1000h"
                expiresIn: "10s"
            });
                res.send({
                    code:200,
                    msg:"登录成功",
                    token:token
                });
            }else{
                res.send({
                    code:0,
                    msg:"登录失败",
                });
            }
        });
    }); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2.返回token并存入vuex做持久化

    //store/index.js
    
    import Vue from 'vue'
    import Vuex from 'vuex'
    import {validate} from '../service/getdata'
    //引入常量函数
    import mutations from './mutations'  
    //vuex注册成为vue的插件
    Vue.use(Vuex)
    const state={
        login: false, //是否登录
        userInfo:null, //用户信息
        userToken:"",//用户登录token
    }
    //通过构造函数创建一个vuex的store
    export default new Vuex.Store({
      //各个组件中共享的数据
      //定义了应用状态的数据结构,其类型可以为string,number,bool,object
      state,
      //定义方法改变状态
      mutations,
      //发送异步请求
      actions: {
        //验证token方法
        async validate({commit}){
          let r = await validate(); //调用user.js中的validate方法,也就是调用验证接口
          if(r.code === 0){
            // commit('setUser',r.username)
            this.userToken=r.token //我们说了,验证通过,或者每次切换路由时,都要重新生成token
          }
          return r.code === 0;  //返回token是否失效,true或者false
        }
    
      },
      //store的计算属性 第一次计算的结果会缓存
      getters(){
    
      },
      modules: {
      }
    }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    3.路由守卫

    //router/index.js
    export default new Router({
      routes: [
        {
          path: '/login',
          name: 'login',
          component: login
        },
        {
          path: '/',
          name: 'Index',
          component: Index,
          //通过添加meta属性,来决定这个页面是否需要登录才能够查看,需要则加这个属性,否则不加
          // meta:{
          //   needLogin:true
          // } 
        }
      ]
    }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    //main.js
    import router from './router'
    import store from './store'
    import axios from 'axios'
    //添加到原型对象
    Vue.prototype.axios=axios;
    //每一次切换路由时,都执行这个导航守卫
    router.beforeEach(async (to,from,next)=>{
      //store.dispatch含有异步操作,数据提交至 actions ,可用于向后台提交数据
      let isLogin = await store.dispatch('validate')  //判断是否登录了
      // needLogin  表示哪些路由需要在登录条件下才能访问
      // console.log(to);
      let needLogin = to.matched.some(match=>match.meta.needLogin)
      if(needLogin){
        //需要登录
        if(isLogin){
          //登录过了
          next()
        }else{
          //没有登录
          next('/login')
        }
      }else{
        //不需要登录
        if(isLogin && to.path === '/login'){  //如果你访问login页面,则给你跳到首页面,因为不需要登录
          // next('/')
        }else{
          next()
        }
      }
    })
    new Vue({
      el: '#app',
      router,
      store,
      components: { App },
      template: '<App/>'
    }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    4.axios请求拦截

    //axios.js,axios的封装,具体可以查其他资料,这里主要展示请求拦截
    import axios from "axios";
    
    //请求拦截
       axios.interceptors.request.use(
            config => {
              console.log('config',config);
              // 从vuex读取token的值,给请求头添加laohu-token
              if (store.state.userToken) {
                  config.headers['user-token'] = store.state.userToken;//如果存在token,将token放入请求头
              }
              return config
          },
            err => {
            return Promise.reject(err)
            }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    总结

    举个栗子:

    1. 发起任意请求axios.get/post(url)
    2. 跳至路由守卫,判断即将跳转的页面是否需要登录,并且现在是否已经登录,请求后端验证端口,返回响应
    3. 假如即将跳转页面需要登录,现在未登录跳转登录页
    4. 用户进行登录,请求后端登录接口,生成token,响应回前端
    5. 前端接收并保存
    6. 再次发起请求,路由守卫判断
    7. 假如即将跳转页面需要登录,现在已经登录,跳至axios请求拦截
    8. 携带token发起请求
    9. 后端接受,返回相应数据

    综上所述:以上就是今天要讲的内容,本文仅仅简单介绍了token的使用,而还没有考虑token失效的情况,下一次再说!

  • 相关阅读:
    解决MySQL 8.0以上版本设置大小写不敏感的问题
    My SQL(二)
    并查集学习心得
    PSI-BLAST位点特异性矩阵PSSM和ProteinMPNN中氨基酸顺序映射
    Opencv+YOLO-V3实现目标跟踪
    这个开学季,注定不平凡
    【Spring(七)】带你手写一个Spring容器
    当OpenHarmony遇上OpenEuler
    vue.js计算机属性01
    Spring概述
  • 原文地址:https://blog.csdn.net/web2022050901/article/details/125486590