• JWT登录验证前后端设计与实现笔记


    设计内容

    前端

    1. 配置全局前置路由守卫
    2. axios拦截器
    3. 登录页面和主页

    后端

    1. JWT的封装
    2. 登录接口
    3. 中间件放行
    4. mysql数据库的连接
      在这里插入图片描述

    详细设计

    路由设计

    配置全局前置守卫,如果访问的是登录页面则放行,不是则进入判断是否有token,没有则拦截回到登录页面,有则放行访问。

    router.beforeEach((to, from, next) => {
      //如果是访问Login,则直接通过
      if(to.name==='Login'){
        next();
      }else{
        //如果没有token则进入登录页面
        if(!localStorage.getItem("token")){
          next({
            path:'/login'
          });
        }else{
            next();
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    axios拦截器

    配置响应拦截器,拿到后端传来的token并保存到localStorage中,如果后端传回来了401错误(token失效),就会删除localStorage中的token并回到登录页面。

    // 响应拦截
    axios.interceptors.response.use(function (response) {
       //拿到响应里的token
       console.log(response);
       const authorization  = response.data.token;
       console.log(authorization);
       authorization && localStorage.setItem("token",authorization);
       return response;
     }, function (error) {
       const { status } = error.response;
       if(status===401){
          localStorage.removeItem("token");
          router.push("/login");
       }
       return Promise.reject(error);
     });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    配置请求拦截器,把localStorage中的token加到请求头中的Authorization中。

    //请求拦截
    axios.interceptors.request.use(function (config) {
       const token = localStorage.getItem("token");
       //请求时带上token,给后端认证
       config.headers.Authorization = `${token}`;
       return config;
     }, function (error) {
       return Promise.reject(error);
     });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    登录页面和主页

    在这里插入图片描述
    登录方法写得比较简单,请求登录接口,判断后端返回的结果。

    LoginHandle(){
       if(this.loginForm.password || this.loginForm.username){
          axios.post("http://localhost:3000/login",this.loginForm).then(res=>{
             if(res.data.status == "success"){
                this.$router.push("/mainbox");
             }else{
                ElMessage.error('用户名或密码错误!');
             }
          })
       }else{
          ElMessage.error('请填写账号和密码!');
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    访问主页时会请求后端的接口,主页请求时所携带的token给后端处理,后端会判断 token是否过期,如果过期后端就回应401错误码,401错误码被axios的响应拦截器处理,跳回登录页面。

    mounted(){
       this.getIndex();
    },
    methods:{
       getIndex(){
          axios.get('http://localhost:3000/bill').then(res=>{
             console.log(res.data);
          })
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    JWT封装

    JWT是JSON Web Token的缩写,jsonwebtoken这个模块有两个常用的方法,sign()和verify()作用分别是生成token和验证token,sign()方法需要3个基本的参数,1.加密内容,2.密钥,3.过期时间。verify()方法有2个基本参数,1.加密内容,2.密钥。

    const jwt = require("jsonwebtoken");
    const secret = "samrol";
    const JWT = {
       generate(value,expires){
          return jwt.sign(value,secret,{expiresIn:expires});
       },
       verify(token){
          try{
             return jwt.verify(token,secret);
          }catch(error){
             return false;
          }
       }
    }
    module.exports = JWT;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    登录接口

    访问/login时后端会做:拿到前端请求带过来的账户和密码,连接数据库,查询登录信息是否正确,不正确则回应登录错误给前端,信息正确:生成token,把token添加到header的Authorization里,返回成功信息。

    const express = require("express");
    const router = express.Router();
    const mysql2 = require("mysql2");
    const JWT = require("../util/JWT");
    const getDBConfig = require("../util/mysql");
    
    router.post("/",async (req,res)=>{
       const {username,password} = req.body;
       const config = getDBConfig();
       const promisePool = mysql2.createPool(config).promise();
       var user = await promisePool.query(`select * from user where name=? and password=?`,[username,password]);
       //登陆成功
       if(user[0].length>0){
          //生成token
          const token = JWT.generate({username,password},"10s");
          //设置头部
          res.header("Authorization",token);
          res.send({status:"success",message:"登录成功",token});
       }else{
          res.send({status:"error",message:"用户名或密码错误"});
       }
    })
    
    module.exports = router;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    补充一个数据库连接配置

    function getDBConfig(){
       return{
          host:'127.0.0.1',
          port:3306,
          user:'root',	
          password:'',
          database:'vue_test',
       }
    }
    
    module.exports = getDBConfig;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    接口拦截中间键

    接收到的每次请求都需要通过这个中间件,如果是login接口则直接放行,其他的则需要通过验证前端携带的token是否过期来判断能否放行,如果过期则返回401错误码来提醒用户token过期需要重新登录。

    app.use((req,res,next)=>{
       if(req.url==="/login"){
          next();
          return;
       }
       const token = req.headers['authorization']//.split(" ")[1];
       if(token){
          var payload = JWT.verify(token);
          if(JWT.verify(token)){
             const newToken = JWT.generate({
                username:payload.username,
                password:payload.password,
             },"10s");
             res.header("Authorization",newToken);
             next();
          }else{
             res.status(401).send({errCode:"-1",errorInfo:"token过期!"});
          }
       }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    Hive学习笔记1
    MFC Windows 程序设计[329]之多彩下拉组合编辑框实例(附源码)
    SpringBoot SpringBoot 开发实用篇 5 整合第三方技术 5.11 jetcache 方法缓存
    git代码管理工具保姆级教学
    内核网络协议栈传输层协议框架
    刷机案例-----谷歌pixel系列机型刷写系统的一些问题解析
    图片水印怎么加?图片加水印方法分享
    游戏合作伙伴专题:BreederDAO 与《王国联盟》结成联盟
    【学习笔记】win11 时间显示秒
    搭建nfs服务器
  • 原文地址:https://blog.csdn.net/qq_26082507/article/details/136137214