vue项目中的登录鉴权

  用vue做一个简单的登录鉴权功能。

项目目录结构如下:

Login 组件

  登录成功后做本地存储和store存储,并进行跳转。

Login.vue关键代码:

    async handleLogin(e) {
      e.preventDefault();
      let parmas = {
        username: this.model.username,
        passwold: this.model.passwold
      };
      const res = await this.$http.get("/api/login", parmas);
      const { code, token, massage } = res.data;
      //code=='0'表示登录成功,进行本地存储和store存储 并进行跳转。
      //else 弹出错误提示
      if (code == "0") {
        this.$store.commit("setToken", res.data.token);
        localStorage.setItem("token", token);
        //如果是由需要鉴权的页面跳转到登录页面 则redirect= this.$route.query.redirect,如果是直接点击登录跳转到登录页面,则redirect= '/'
        const redirect = this.$route.query.redirect || "/";
        this.$router.push(redirect);
      } else {
        const toast = this.$createToast({
          time: 2000,
          txt: massage || "登录失败",
          type: "error"
        });
        toast.show();
      }
    }

store

  在Login组件里登录时token做了数据持久化处理,防止页面刷新丢失token。给store里的token赋初值的时候要取

store.js关键代码:

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    //token数据持久化,防止页面刷新丢失
    token: localStorage.getItem('token') || ''
  },
  mutations: {
    setToken(state, token) {
      state.token = token
    }
  },
  actions: {

  },
  getters: {
    //根据token是否存在,设置计算属性isLogin
    isLogin(state) {
      return !!state.token
    }
  }
})

router

  routes[]里用 mate.auth来标识是否需要鉴权。router.beforeEach做个全局路由守卫,根据是否需要鉴权以及是否已经登录来进行不同操作。

router.js代码:

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import Login from './views/Login.vue';
import store from './store';
Vue.use(Router)

const router = new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    },
    {
      path: '/about',
      name: 'about',
      meta: { auth: true },//about需要做登录鉴权
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
})
router.beforeEach((to, from, next) => {
  //to.meta.auth 表示需要做登录健全
  //不需要的 可以直接next
  if (to.meta.auth) {
    //store.state.token 表示已经登录 可以直接next
    //没有登录 跳转到/login 并携带参数redirect 方便登录后直接跳转到to.path
    if (store.state.token) {
      next();
    } else {
      next({
        path: '/login',
        query: { redirect: to.path }
      })
    }
  } else {
    next();
  }
})
export default router;

axios拦截  

  axios.interceptors.request.use拦截axios所有http请求,如果存在token,则放入请求头。axios.interceptors.response.use拦截的axios的响应,如果token以及失效,则清除本地缓存和store存储并跳转到登录页面。

http-interceptors.js代码:

import axios from "axios";
import store from "./store";
import router from "./router";
// 拦截axios所有http请求,预先放入token请求头
axios.interceptors.request.use(config => {
  if (store.state.token) {
    // 若存在token,则放入请求头
    config.headers.token = store.state.token;
  }
  return config;
});

// 响应拦截器,提前预处理响应
axios.interceptors.response.use(
  response => {
    // 如果code是-1,说明用户已注销或者token已过期
    // 此时需要重新登录,并且还要清除本地缓存信息和store数据
    if (response.status == 200) {
      const data = response.data;
      if (data.code == -1) {
        logoutFun()
      }
    }
    return response;
  },
  err => {
    if (err.response.status === 401) { // 未授权
      logoutFun()
    }
  }
);

function logoutFun() {
  // 清空本地缓存的token和store里的token
  store.commit("setToken", "");
  localStorage.removeItem("token");
  // 跳转至登录页,并携带用户退出时或token失效时的页面路由,方便登录后直接跳转到此页面。
  router.push({
    path: "/login",
    query: {
      redirect: router.currentRoute.path
    }
  });
}
服务端中间件
  服务端也需要做请求处理的中间件。如果请求不是req.path不是'/api/login'并且没有携带token,则返回错误状态码401。
vue.config.js关键代码:
        app.use((req, res, next) => {
          //只对api开头的请求做拦截处理
          if (/^/api/.test(req.path)) {
            if (req.path == '/api/login' || req.headers.token) {
              next();
            } else {
              //设置错误状态码为401
              res.sendStatus('401')
              next();
            }
          } else {
            next();
          }
        })
原文地址:https://www.cnblogs.com/superlizhao/p/10991300.html