欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vue框架+axios实现登录守卫(验证token是否存在以及过期)

程序员文章站 2022-07-03 07:58:13
...

vue框架+axios实现登录守卫(token)

做项目的时候需要用到登录成功跳转到首页的功能,并且首页没有登录需要自动跳蛛到登录,这就要求设置axios,配置请求拦截器、响应拦截器。把学到的笔记记录并且下来,方便下次回忆。
首先前后端数据库服务器等我已经配置好了,单个页面都可以使用的。

这次用到了本地存储,当登录成功后,本地存储会保存token,实现跨域登录。当token失效后,会删除本地存储中的token,则需要跳转到登录页面。
这是服务器端的目录
vue框架+axios实现登录守卫(验证token是否存在以及过期)
这里是vue框架的目录
vue框架+axios实现登录守卫(验证token是否存在以及过期)
项目依赖
vue框架+axios实现登录守卫(验证token是否存在以及过期)
login.vue

<template>
  <div class="login">
    <el-form
      :model="loginUser"
      status-icon
      :rules="rules"
      ref="ruleForm"
      label-width="100px"
      class="loginUser"
      
    >
      <el-form-item label="手机号" prop="tel">
        <el-input v-model="loginUser.tel" autocomplete="off"></el-input>
      </el-form-item>
       <el-form-item label="密码" prop="password">
        <el-input  type="password"  v-model="loginUser.password"></el-input>
      </el-form-item>
           
      <el-form-item>
        <el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
        <el-button @click="resetForm('ruleForm')">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  name: "login",
  data: function() {
    return {
      loginUser: {
        tel: "12323452345",
        password: "123456"
        //这里写成默认方便测试,可以自己清空,输入数据库的东西
      },
      rules: {
        tel: [
          { required: true, message: "手机号不能为空", trigger: "blur" }, //required,必须不能为空
          //blur,光标离开失去焦点
          { min: 11, max: 11, message: "手机号码必须是11位", trigger: "blur" }
        ],
        password: [
          { required: true, message: "密码不能为空", trigger: "blur" }, //required,必须不能为空
          //blur,光标离开失去焦点
          { min: 6, max: 6, message: "密码必须是6位", trigger: "blur" }
        ]
      }
    };
  },
  methods: {
    submitForm(formName) {
        //通过ref定位到form表单
      this.$refs[formName].validate(valid => {
        if (valid) {
          alert("登录成功!");
          this.$axios.post('http://localhost:3000/users/login',this.loginUser)
          .then(res =>{
            console.log('登录成功' ,res)
            this.$router.push('/index');
          })
          .catch(err =>{
            console.log(err)
          })
        } else {
          console.log("提交失败!!");
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    }
  }
};
</script>

<style lang="css" scoped>
.login {
  width: 100%;
  height: 100%;
  background: url("../assets/980.jpg") no-repeat center center;
  background-size: 100% 100%;
}
.loginUser {
  width: 400px;
  height: 380px;
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -200px;
  margin-top: -190px;
  border-radius: 5px;
  background-color: #fff;
  padding: 20px 50px 10px 10px;
}
</style>

这里是userController.js,userDao这里没什么需要更改的暂且不记

 login: function (req, res) {
        //接收用户请求传入的参数,并创建用户对象
        var user = { tel: req.body.tel, password: req.body.password }
        userDAO.getUserByTel(user.tel, function (err, results) {
            if (err) {
                res.status(500).json({ msg: '数据库错误,登录失败!' })
            } else {
                if (results == null || results.length != 1) {
                    res.status(200).json({ msg: '手机号不存在,登录失败!' })
                } else {
                    bcrypt.compare(user.password, results[0].password, function (err, resPwd) {
                        // res == true
                        if (resPwd) {
                            
                            //记录登录成功后的token ,expiresIn用的是10s,方便跳转验证
                            jwt.sign({ tel: user.tel }, 'privateKey', { expiresIn:10 }, function (err, token) {
                                console.log(token);
                                //注意token的固定格式“Bearer ”前缀
                                res.status(200).json({ msg: '登录成功!!', token: 'Bearer ' + token })
                            });
                        } else {
                            res.status(200).json({ msg: '密码错误,登录失败!!' })
                        }
                    });
                }
            }
        })
    },

当然需要配置目录config里面passport.js

//用于验证token的模块
var JwtStrategy = require('passport-jwt').Strategy,
    ExtractJwt = require('passport-jwt').ExtractJwt;
var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = 'privateKey';
function myPassport(passport){
    passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
        //jwt_payload保存的是token生成时的对象
       
       console.log(jwt_payload)
       //通过验证后执行下一步
       done(null,jwt_payload)
    }));
}
module.exports = myPassport

首先app.js里面跨域请求需要的操作要有
这里的localhost:8080就是我vue请求跳转界面要用到的头部
需要注意的是,在Access-Control-Allow-Headers里面要添加Authorization,这个是处理401状态码要用到的东西。

//设置跨域请求的允许操作
app.all('*', function (req, res, next) {
  // res.header('Access-Control-Allow-Origin', '*'); //针对所有请求用户都允许
  res.header('Access-Control-Allow-Origin', 'http://localhost:8080'); //针对指定的请求用户允许,其他用户禁止访问
  res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization');
  res.header('Access-Control-Allow-Methods', '*');
  res.header('Access-Control-Allow-Credentials', 'true');
  next()
})

接着login.vue里面需要加一下东西,箭头指向处
vue框架+axios实现登录守卫(验证token是否存在以及过期)

  console.log(res.data.token)//在控制台查看输出的token
            console.log('token对象',jwt_decode(res.data.token))//解析token
            localStorage.setItem('mytoken',res.data.token)//本地存储
            this.$router.push('/index');//登录成功后跳转到index.vue页面

vueproj里面router.js当然也要设置,都给复制过来了,代码上有注释

import Vue from 'vue'
import Router from 'vue-router'
import Index from './views/Index.vue'
import Login from './views/Login.vue'
import Register from './views/Register.vue'
import Not404 from './views/Not404.vue'

Vue.use(Router)
let router = new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
     redirect:'/index'
    },
    {
      path: '/index',
      name: 'index',
      component: Index
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    },
    {
      path: '/register',
      name: 'register',
      component: Register
    }
  ]
})

//设置路由守卫
//设置路由守卫
router.beforeEach((to,from,next) => {
  //除了login和register,其他的路由访问必须先登录
  let tokenIsExists = localStorage.getItem('mytoken') ? true : false //检查本地存储中是否有token
  if(to.path == '/login' || to.path == '/register'){
    next()    //允许访问路由
  }else{
    if(tokenIsExists){
      next()  //已经登录并取得token,允许访问路由
    }else{
      next('/login')  //路由跳转到登录组件
    }
  }
})
export default router

接下来设置下http.js里面的内容,我都给粘贴进去了,里面有拦截token以及token过期的处理

import axios from 'axios'
import router from './router'
//设置axios,配置请求拦截器、响应拦截器
axios.interceptors.request.use(function (config) {
    //当调用带鉴权的接口时,添加token头部标志
    if(localStorage.getItem('mytoken')){
        //在请求头部中加入token
        config.headers.Authorization = localStorage.getItem('mytoken')
    }
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });
 
// 响应拦截器
axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
      //当token过期时,获取错误信息,并清除本地存储的过期token
      if(error.response.status == 401){
        localStorage.removeItem('mytoken')
        router.push('/login')   //跳转到登录组件
      }
    return Promise.reject(error);
  });
export default axios

index.vue里面需要修改添加的

<script>

export default{
    data(){
      return {
        students:[],
        currentUser:{}
      }
    },
    //组件创建完成后执行的操作
    created(){
      this.$axios.get('http://localhost:3000/users')
      .then(res => {
        console.log( '查询结果:',res.data.data)
        this.students = res.data.data
      })
      .catch(err => {
        console.log('错误信息:' ,err)
      })
    }
}
</script>

最后测试一下
当本地存储没有的时候进入index首页,会直接跳转到login页面
vue框架+axios实现登录守卫(验证token是否存在以及过期)
登录成功后可以看到本地存储里面有我的token了,此时控制台里面也有我想要的数据
vue框架+axios实现登录守卫(验证token是否存在以及过期)
vue框架+axios实现登录守卫(验证token是否存在以及过期)
由于设置token的时限为10s,当过了10s后刷新就会再次进入login页面重新登录