Vue项目中实现用户登录及token验证以及封装全局api请求拦截器

405 阅读2分钟

在前后端完全分离的情况下,Vue项目中实现token验证大致思路如下:

1、首先新建一个api.js来全局处理接口调用

//添加一个请求拦截器
axios.interceptors.request.use(function(config) {
    config.headers.token = store.state.token
    return config;
}, function(error) {	
	alert('token不存在!')
    return Promise.reject(error);
});

// 添加一个响应拦截器
axios.interceptors.response.use(function(response) {
    if (response.data.Code == 10001) {
        //未登录
		alert(response.data.data)
        localStorage.removeItem('access-user')
        routerIndex.push('/login');
    }else if(response.data.Code == 10002){
        //token过期
        alert(response.data.data)
        localStorage.removeItem('access-user')
        routerIndex.push('/login');
    }    
    return response;
}, function(error) {
    return Promise.reject(error);
});

let base = window.g.BASE_URL;

//通用方法
export const POST = (url, params) => {
    return axios.post(`${base}${url}`, params).then(res => res.data)
}
export const GET = (url, params) => {
    return axios.get(`${base}${url}`, { params: params }).then(res => res.data)
}

2、接口调用方法:

import * as API from './api.js'

export default {
  //登录
  login: params => {    
    return API.POST('/api/system/login', params).then(res => res)  
    //return "success";
  }
}

3、路由守卫方法:

import Vue from 'vue';
import Router from 'vue-router';
import login from '@/components/login';
import home from '@/components/home';
 
Vue.use(Router);
 
const router = new Router({
  routes: [   
    {
      path: '/login',
      name: 'login',
      component: login
    },
    {
      path: '/home',
      name: 'home',
      component: home
    }
  ]
});
 
// 导航守卫
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
router.beforeEach((to, from, next) => {
    if (to.path.startsWith('/login')) {
        window.localStorage.removeItem('access-user')
        next()
    } else {
        let token = localStorage.getItem('token');
        let user = JSON.parse(window.localStorage.getItem('access-user'))        
        if (!user && token === null || token === '') {
            next({ path: '/login' })
        } else {
            next()
        }
    }
});
 
export default router;

4、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码

<el-form ref="AccountForm" :model="account" :rules="rules" label-position="right" label-width="70px">
 <el-form-item prop="userName" label="账号:">
        <el-input type="text" v-model="account.userName" class="i-input-txt" maxlength="32" auto-complete="off" autofocus="true" placeholder="请输入账号手机号或邮箱"></el-input>
      </el-form-item>
      <el-form-item prop="password" label="密码:">
        <el-input type="password" v-model="account.password" class="i-input-txt" maxlength="32" :autofocus="pwdFocus" auto-complete="off" placeholder="请输入登录密码" @keyup.enter="handleLogin"></el-input>
      </el-form-item>
      <el-form-item class="no-item-f">
        <el-button type="primary" style="width:100%;" @click="handleLogin">登录</el-button>
      </el-form-item>
</el-form>

import { mapMutations } from 'vuex';
data() {
    return {     
        account: {
          userName: '',
          password: ''
        }, 
    }
},
methods: {
...mapMutations(['changeLogin']),
handleLogin(event){    
        let codestatus = this.checkCode();  
        if (codestatus) {
          let params = {          
            userName: this.account.userName,  
            password: this.account.password
          }; 
          //调用函数  传递参数 获取结果
          API.login(params).then(res=>{
              if(res.code == '200'){  
                   //登录成功                
                  localStorage.setItem('access-user', JSON.stringify(res.data));
                  this.$cookieStore.setCookie('userName' ,res.data.account, 120);
                  
                  // 将用户token保存到vuex中                        
                  this.changeLogin({token:res.token}); 
                  this.$router.push('/home');                                 
              }else{
                  console.log(res.code);
                  messageOnce.error({message: '登录失败,账号或密码错误!',type: 'error'})   
                  return false;
              }
          })
        } 
      }
}

store文件夹下的index.js:

/**
 * Created by byh on 2020/5/10.
 */
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
const state = {   
    token: null // 存储token
}
const mutations = {
    // 修改token,并将token存入localStorage
    changeLogin(state, user) {
        state.token = user.token;
        localStorage.setItem('token', user.token);
    },
    // 删除token  
    quitLogin(state) {
        state.token = null
        localStorage.removeItem('token');
    }
}

/*从本地存储读取数据*/
for (var item in state) {
    localStorage.getItem(item) ? state[item] = localStorage.getItem(item) : false;
}
export default new Vuex.Store({
    state,
    mutations
})

5、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token,前端拿到token,将token存储到localStorage和vuex中,并跳转路由页面,前端每次跳转路由,就判断 localStroage 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面,每次调后端接口,都要在请求头中加token,后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401,如果前端拿到状态码为401,就清除token信息并跳转到登录页面!