Vue后台管理系统用户认证封装

在使用vue技术栈开发各类管理系统时,经常需要相同的开发目录架设。在日常开发中,整理了一套自己的开发目录。主要包括vuejsvue-routervuexaxios等常用类库。

开发依赖

 "vuex": "^3.1.0",
 "babel-polyfill": "^6.26.0",
 "element-ui": "^2.9.1",
 "vue": "^2.5.2",
 "vue-router": "^3.0.1",
 "axios": "^0.18.0",

Git仓库地址

vue-template

开发目录

vue-template主要使用axios做请求处理,在src/api/index.js中对axios做了二次封装,然后把封装函数gl_ajax挂载在全局vue.prototype上,通过各层嵌套组件通过原型可以获取gl_ajax函数。在router/index.js主要是路由定义和路由导航守卫功能。详细情况可以参考提供源码地址。

|-- App.vue(挂载根组件)
|-- api(封装请求相关模块)
|   |-- api.js(公用api接口定义)
|   |-- config.js(项目请求地址和其他参数)
|   |-- index.js(axios二次封装定义)
|-- components(公用业务组件)
|-- main.js(程序执行入口)
|-- plugins(开发vue插件目录)
|   |-- el_icon(Icon组件)
|   |   |-- Icon.vue
|   |   |-- assets
|   |   |   |-- error.svg
|   |   |   |-- info.svg
|   |   |   |-- success.svg
|   |   |   |-- warning.svg
|   |   |-- index.js
|   |-- el_message(message提示组件)
|       |-- index.js
|       |-- main.js
|       |-- message.vue
|-- router(路由定义和路由守卫)
|   |-- index.js
|-- store(vuex定义和action)
|   |-- index.js
|   |-- types.js
|-- views(业务组件)
    |-- Home.vue
    |-- Login.vue
    |-- index.vue

main入口

main入口对类库进行挂载,二次封装的函数gl_ajax、第三方组件库elementuivue官方提议对挂载在vue原型链上的自定义函数加前缀$区分,这里使用alias:$gl_ajax来进行挂载。

import Vue from "vue";
import "babel-polyfill";
import App from "./App";
import router from "./router";
import store from "./store/index.js";
import { gl_ajax } from "./api/index.js";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
Vue.prototype.$gl_ajax = gl_ajax;
Vue.config.productionTip = false;
Vue.use(ElementUI);
new Vue({
  el: "#app",
  store,
  router,
  components: { App },
  template: "<App/>"
});

路由定义和路由守卫

开发后台管理系统,某些页面需要对用户或游客进行权限验证。所以在路由文件添加路由守卫,阻止未登录用户对需权限的页面的操作。

在使用vue中采取前后端分离的形式,通过JWT获取对api接口的请求权限token,在登录中获取token,然后保存在sessionStorage中,之所以不把token保存在vuex中,是因为浏览器刷新会导致store数据重置。失去登录token。这里采用的是sessionStoragevuex的形式,避免了上述的弊端。

// 页面刷新时,重新赋值token
if (window.sessionStorage.getItem("token")) {
  store.commit(types.LOGIN, window.sessionStorage.getItem("token"));
}

下面是router/index.js的完整定义源码

import Vue from "vue";
import VueRouter from "vue-router";
import store from "../store/index";
import * as types from "../store/types";
Vue.use(VueRouter);
const routes = [{
    path: '',
    redirect: '/login'
  }, {
    path: "/",
    component: resolve => require(["@/views/Home"], resolve),
    children: [{
      path: '/admin',
      name: 'admin',
      component: resolve => require(["@/views/index"], resolve)
    }]
  },
  {
    path: "/login",
    name: "Login",
    component: resolve => require(["@/views/Login"], resolve)
  }
];

// 页面刷新时,重新赋值token
if (window.sessionStorage.getItem("token")) {
  store.commit(types.LOGIN, window.sessionStorage.getItem("token"));
}

const router = new VueRouter({
  mode: "history",
  routes
});

//路由导航守卫
router.beforeEach((to, from, next) => {
  if (to.path == "/login") {
    store.commit(types.LOGOUT);
    next();
  } else {
    const token = sessionStorage.getItem("token");
    if (!token) {
      next({
        path: "/login",
        query: {
          redirect: to.fullPath
        }
      });
    } else {
      next();
    }
  }
});
export default router;

全局数据储存vuex

在路由导航中,使用storesessionStorage形式保存登录token,在store/index.js中也定义了登录和退出操作mutations

把退出操作定义在store中,是为了下面对登录权限过期,返回401状态码,进行重定向操作功能。

import Vue from "vue";
import Vuex from "vuex";
import * as types from "./types";
Vue.use(Vuex);
export default new Vuex.Store({
  state: {
    token: null
  },
  mutations: {
    [types.LOGOUT]: (state, data) => {
      sessionStorage.removeItem("token");
      state.token = null;
    },
    [types.LOGIN]: (state, data) => {
      sessionStorage.setItem("token", data);
      state.token = data;
    }
  },
  actions: {},
  getters: {}
});

axios封装

api/index.js文件中对axios进行了二次封装。同一根目录下config.js定义请求超时时间、开发和线上请求URL

axios请求拦截

axios请求错误拦截是重点部分。主要对权限过期401和请求超时操作store对保存的token清除,然后再对路由进行重定向。

axios.interceptors.response.use(
  response => {
    return response;
  },
  error => {
    if (error.response) {
      switch (error.response.status) {
        case 401:
          store.commit(types.LOGOUT);
          router.replace({
            path: "/login",
            query: {
              redirect: router.currentRoute.path
            }
          });
      }
      const message = error.response.data.message ?:'未知错误';
      Message.error(message);
    } else if (error.code == 'ECONNABORTED' && error.message.indexOf('timeout') != -1) {
      Message.error("请求已超时");
    }
    return Promise.reject(error);
  }
);
gl_ajax请求封装

responseTypeaxios请求文件下载需要的接受类型,文件是通过application/json方式进行获取。

export const gl_ajax = params => {
  return axios({
      method: params.method.toLowerCase(),
      url: `${axios.defaults.baseURL}${params.url}`,
      data: params.method != "get" ? params.data : "",
      params: params.method == "get" ? params.data : "",
      responseType: params.file ? "blob" : ""
    })
    .then(res => {
      params.success && params.success(res);
    })
    .catch(err => {
      params.error && params.error(err);
    });
};

gl_ajax使用

vue的原型上定义了$gl_ajax函数,在login常见登录中需要请求接口获取token权限,下面对$gl_ajax介绍使用方式和对token保存操作。

self.$store.commit(types.LOGIN,token)vuex中保存token,会在sessionStoragestore分别保存一份token值。防止浏览器刷新造成vuextoken丢失。

<template>
    <div>
        <button @click='loginSystem'>login</button>
    </div>
</template>
<script>
import * as types from "../store/types.js";
export default {
  name: "Login",
  data() {
    return {};
  },
  methods: {
    loginSystem() {
      const self = this;
      this.$gl_ajax({
        url: "/login",
        method: "post",
        data: { ...self.loginData },
        success(res) {
          if (res.data.status == "ok") {
            const token = res.data.jwt;
            self.$store.commit(types.LOGIN, token);
            self.message("login success");
            self.$router.push({
              path: "/admin"
            });
          }
        },
        error(err) {}
      });
    }
  }
};
</script>
<style>
</style>

如果觉得有帮助,可以给个赞或star

github地址:vue-template

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容